#librerias necesarias


#library (Biostrings) # Manipulacion de secuencias y alineamientos

library(ggplot2)
library(plotly)
library (RColorBrewer)
library(caret)
library(tidyr)
library(dplyr)
#library(reshape2)
library(psych)
library(irlba)
library(fpc)

Data

#librerias necesarias
#library (Biostrings) # Manipulacion de secuencias y alineamientos
library(ggplot2)
library(plotly)
library (RColorBrewer)
library(caret)
library(tidyr)
library(dplyr)
#library(reshape2)
library(psych)
library(irlba)
library(fpc)

NSFW

train_v1<-read.csv("ccs.new_train_v1.csv", stringsAsFactors = FALSE)%>%select(-id)
trainCat<-train_v1%>%select(type_cat, image_name)
test_v1<-read.csv("ccs.new_test_v1.csv" , stringsAsFactors = FALSE)%>%select(-id)

Distance

NSFWtrain<-read.csv("nsfwOut_train.csv" , stringsAsFactors = FALSE, header=FALSE)%>%
                rename(image_name=V1, nsfw_val=V2)%>%
                    mutate(nsfw_val_log=log(nsfw_val))
NSFWtest<-read.csv("nsfwOut_test.csv" , stringsAsFactors = FALSE, header=FALSE)%>%
  
                rename(image_name=V1, nsfw_val=V2)%>%
                    mutate(nsfw_val_log=log(nsfw_val))
NSFWtrain<-left_join(trainCat,NSFWtrain, by=c("image_name"="image_name"))
NSFWtrain%>%
  spread(type_cat, nsfw_val)%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~Type_1, name="Type_1") %>%
          add_histogram(x = ~Type_2,name="Type_2" ) %>%
           add_histogram(x = ~Type_3, name="Type_3" ) %>%
        layout(barmode = "overlay",title = "NSFW value")

## Logaritmic
NSFWtrain%>%
  spread(type_cat, nsfw_val)%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~log(Type_1), name="Type_1") %>%
          add_histogram(x = ~log(Type_2),name="Type_2" ) %>%
           add_histogram(x = ~log(Type_3), name="Type_3" ) %>%
        layout(barmode = "overlay", title = "log(NSFW value)")

##Check consistency at both sets
head(cbind(train.mean = lapply(NSFWtrain%>%select(nsfw_val,nsfw_val_log),
                               function(x){mean(x,na.rm=TRUE)} ),
              train.sd = lapply(NSFWtrain%>%select(nsfw_val,nsfw_val_log),
                            function(x){sd(x,na.rm=TRUE)} ),
                 test.mean = lapply(NSFWtest%>%select(nsfw_val,nsfw_val_log),
                                   function(x){mean(x,na.rm=TRUE)}),
                      test.sd = lapply(NSFWtest%>%select(nsfw_val,nsfw_val_log),
                                       function(x){sd(x,na.rm=TRUE)})))
             train.mean train.sd test.mean test.sd  
nsfw_val     0.2106212  0.25315  0.2378719 0.2669555
nsfw_val_log -2.463487  1.577257 -2.298662 1.570717 

hashing

Distrain<-read.csv("train_distance.csv" , stringsAsFactors = FALSE,
                   header=FALSE)%>%
                     rename(image_name=V1, dist_val=V2)%>%
                        mutate(dist_val_log=log(dist_val))
  
Distest<-read.csv("test_distance.csv" , stringsAsFactors = FALSE,
                  header=FALSE)%>%
                      rename(image_name=V1, dist_val=V2)%>%
                          mutate(dist_val_log=log(dist_val))
Distrain<-left_join(trainCat,Distrain, by=c("image_name"="image_name"))
##Check consistency at both sets
head(cbind(train.mean = lapply(Distrain%>%select(dist_val,dist_val_log),
                               function(x){mean(x,na.rm=TRUE)} ),
              train.sd = lapply(Distrain%>%select(dist_val,dist_val_log),
                            function(x){sd(x,na.rm=TRUE)} ),
                 test.mean = lapply(Distest%>%select(dist_val,dist_val_log),
                                   function(x){mean(x,na.rm=TRUE)}),
                      test.sd = lapply(Distest%>%select(dist_val,dist_val_log),
                                       function(x){sd(x,na.rm=TRUE)})))
             train.mean train.sd  test.mean test.sd  
dist_val     6449660    1872454   6249978   1914739  
dist_val_log 15.61894   0.3911204 15.57813  0.4301607
#scale train
Distrain_s<- scale(as.matrix(Distrain%>%select(dist_val, dist_val_log)),
                   center=TRUE,scale=TRUE)
#scale testing
Distest_s<- scale(as.matrix(Distest%>%select(dist_val, dist_val_log),
                                attr(Distrain_s, "scaled:center"),
                                    attr(Distrain_s, "scaled:scale") ) )
##Transform both sets
Distrain<-cbind(Distrain%>%select(type_cat, image_name) , Distrain_s[,])
Distest<-cbind(Distest%>%select( image_name) , Distest_s[,])
Distrain%>%
  spread(type_cat, dist_val)%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~Type_1, name="Type_1") %>%
          add_histogram(x = ~Type_2,name="Type_2" ) %>%
           add_histogram(x = ~Type_3, name="Type_3" ) %>%
        layout(barmode = "overlay",
               title = "Distance")

### Logaritm
Distrain%>%
  spread(type_cat, dist_val)%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~log(Type_1), name="Type_1") %>%
          add_histogram(x = ~log(Type_2),name="Type_2" ) %>%
           add_histogram(x = ~log(Type_3), name="Type_3" ) %>%
        layout(barmode = "overlay",
               title = "Log (Distance)")

## Check
Distrain[1:5,1:4]
Distest[1:5,1:3]
##Check consistency at both sets
head(cbind(train.mean = lapply(Distrain%>%select(dist_val,dist_val_log),
                               function(x){mean(x,na.rm=TRUE)} ),
              train.sd = lapply(Distrain%>%select(dist_val,dist_val_log),
                            function(x){sd(x,na.rm=TRUE)} ),
                 test.mean = lapply(Distest%>%select(dist_val,dist_val_log),
                                   function(x){mean(x,na.rm=TRUE)}),
                      test.sd = lapply(Distest%>%select(dist_val,dist_val_log),
                                       function(x){sd(x,na.rm=TRUE)})))
             train.mean    train.sd test.mean     test.sd
dist_val     -8.890245e-17 1        -2.942804e-18 1      
dist_val_log -2.192649e-15 1        4.123298e-16  1      

Networks

pHashtrain<-read.csv("hashes_16_phash_training.csv" , stringsAsFactors = FALSE, header=FALSE)%>%select(-V2)%>%
          #mutate_each(funs(whatever = ./15), V3:V66)
            mutate_each(funs(./15), V3:V66)
pHashtest<-read.csv("hashes_16_phash_testing.csv" , stringsAsFactors = FALSE, header=FALSE)%>%select(-V2)%>%
          mutate_each(funs(./15), V3:V66)
### REMOVE NEAR ZERO VARIATION
nzv_11<- nearZeroVar(pHashtrain)
nzv_12<- nearZeroVar(pHashtest)
if(length(unique(c(nzv_11,nzv_12)))>0)
      {
        pHashtrain<- pHashtrain[, -unique(c(nzv_11,nzv_12))]
        pHashtest<- pHashtest[, -unique(c(nzv_11,nzv_12))]
        }
##Check consistency at both sets
head(cbind(train.mean = lapply(pHashtrain[,-1], mean),
          train.sd = lapply(pHashtrain[,-1], sd),
                test.mean = lapply(pHashtest[,-1], mean),
                      test.sd = lapply(pHashtest[,-1], sd)))
   train.mean train.sd  test.mean test.sd  
V3 0.4498535  0.3162274 0.4458333 0.3241125
V4 0.4669371  0.2922544 0.4648438 0.2949693
V5 0.4714447  0.3191498 0.4415365 0.3182941
V6 0.4573811  0.3190504 0.4592448 0.3193908
V7 0.5020509  0.3150338 0.4847656 0.3218135
V8 0.4611675  0.285993  0.4653646 0.2834234
# conduct PCA on training dataset
num.cols <- names(which(sapply( pHashtrain, function(x) is.numeric(x) )))
pca <- prcomp(pHashtrain[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)
### Plot importance
p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                    geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~pixel features ")
ggplotly(p)

#Replace features by PCA components
pHashtrain_pca<-as.data.frame(pca$x[,1:40])
colnames(pHashtrain_pca)<-paste("pca_pHash_",1:40,sep="")
### APPLY TO TESTING DATA 
pHashtest_pca<-as.data.frame(predict(pca, newdata=pHashtest[,num.cols])[,1:40])
colnames(pHashtest_pca)<-paste("pca_pHash_",1:40,sep="")
pHashtrain<-cbind(pHashtrain[,1],pHashtrain_pca)
pHashtest<-cbind(pHashtest[,1],pHashtest_pca)
colnames(pHashtrain)[1]<-colnames(pHashtest)[1]<-"image_name"
pHashtrain<-left_join(trainCat,pHashtrain, by=c("image_name"="image_name"))
#### Plot Four first dimensions
p <- plot_ly(pHashtrain, x = ~pca_pHash_1, y = ~pca_pHash_2, color = ~as.factor(type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))
p

pHashtrain[1:5,1:5]
pHashtest[1:5,1:5]

InceptionV3 Net

Namestrain<-read.csv("Names_train_features.csv" , stringsAsFactors = FALSE)
Namestest<-read.csv("Names_test_features.csv" , stringsAsFactors = FALSE)
##### Inceptionv3
Inceptrain<- cbind(Namestrain,read.csv("Inception3_train_features.csv", stringsAsFactors = FALSE) )
Inceptest<- cbind(Namestest, read.csv("Inception3_test_features.csv", stringsAsFactors = FALSE) )
##### ResNet50
RN50train<-cbind(Namestrain, read.csv("ResNet50_train_features.csv", stringsAsFactors = FALSE) )
RN50test<-cbind(Namestest ,read.csv("ResNet50_test_features.csv", stringsAsFactors = FALSE) )
#####VGG19 
VGG19train<-cbind(Namestrain ,read.csv("VGG19_train_features.csv" , stringsAsFactors = FALSE) )
VGG19test<-cbind(Namestest, read.csv("VGG19_test_features.csv" , stringsAsFactors = FALSE) )

ResNet50 Net

### REMOVE NEAR ZERO VARIATION
nzv_11<- nearZeroVar(Inceptrain)
nzv_12<- nearZeroVar(Inceptest)
if(length(unique(c(nzv_11,nzv_12)))>0)
      {
        Inceptrain<- Inceptrain[, -unique(c(nzv_11,nzv_12))]
        Inceptrain<- Inceptest[, -unique(c(nzv_11,nzv_12))]
        }
##Check consistency at both sets
head(cbind(train.mean = lapply(Inceptrain[,-1], mean),
          train.sd = lapply(Inceptrain[,-1], sd),
                test.mean = lapply(Inceptest[,-1], mean),
                      test.sd = lapply(Inceptest[,-1], sd)))
   train.mean   train.sd     test.mean    test.sd    
X0 0.001380052  0.01141086   0.0009170967 0.002802622
X1 0.003639353  0.0210514    0.00374452   0.02601869 
X2 0.0005113326 0.001457968  0.0004813768 0.001247876
X3 0.0005140099 0.001690451  0.0004951666 0.002232964
X4 0.0003072042 0.0007335646 0.000539596  0.005894615
X5 0.001228221  0.0157454    0.001042944  0.01056041 
#### Plot first
Inceptrain%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~X0, name="X0") %>%
          add_histogram(x = ~X1,name="X1" ) %>%
           add_histogram(x = ~X2, name="X2" ) %>%
              add_histogram(x = ~X3, name="X3" ) %>%
                add_histogram(x = ~X4, name="X4" ) %>%
                    add_histogram(x = ~X5, name="X5" ) %>%
                      add_histogram(x = ~X6, name="X6" ) %>%
                           add_histogram(x = ~X7, name="X7" ) %>%
                                add_histogram(x = ~X8, name="X8" ) %>%
                                     add_histogram(x = ~X9, name="X9" ) %>%
                                        add_histogram(x = ~X10, name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "Inceptrain_outputs")

#### Plot log
Inceptrain%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~log(X0), name="X0") %>%
          add_histogram(x = ~log(X1),name="X1" ) %>%
           add_histogram(x = ~log(X2), name="X2" ) %>%
              add_histogram(x = ~log(X3), name="X3" ) %>%
                add_histogram(x = ~log(X4), name="X4" ) %>%
                    add_histogram(x = ~log(X5), name="X5" ) %>%
                      add_histogram(x = ~log(X6), name="X6" ) %>%
                           add_histogram(x = ~log(X7), name="X7" ) %>%
                                add_histogram(x = ~log(X8), name="X8" ) %>%
                                     add_histogram(x = ~log(X9), name="X9" ) %>%
                                        add_histogram(x = ~log(X10), name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "log(Inceptrain_outputs)")

####################################################################################################
####################################################################################################
# conduct PCA on training dataset
num.cols <- names(which(sapply( Inceptrain, function(x) is.numeric(x) )))
pca <- prcomp(Inceptrain[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)
### Plot importance
p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                    geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~Inceptrain features ")
ggplotly(p)

####################################################################################################
####################################################################################################
####################################################################################################
#Replace features by PCA components
Inceptrain_pca<-as.data.frame(pca$x[,1:50])
colnames(Inceptrain_pca)<-paste("pca_Incep3_",1:50,sep="")
### APPLY TO TESTING DATA 
Inceptest_pca<-as.data.frame(predict(pca, newdata=Inceptest[,num.cols])[,1:50])
colnames(Inceptest_pca)<-paste("pca_Incep3_",1:50,sep="")
Inceptrain<-cbind(Inceptrain[,1],Inceptrain_pca)
Inceptest<-cbind(Inceptest[,1],Inceptest_pca)
colnames(Inceptrain)[1]<-colnames(Inceptest)[1]<-"image_name"
Inceptrain<-left_join(trainCat,Inceptrain, by=c("image_name"="image_name"))
#### Plot Four first dimensions
p <- plot_ly(Inceptrain, x = ~pca_Incep3_1, y = ~pca_Incep3_2, color = ~as.factor(type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))
p

#### Plot first
Inceptrain%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~pca_Incep3_1, name="cmp1") %>%
          add_histogram(x = ~pca_Incep3_2,name="cmp2" ) %>%
           add_histogram(x = ~pca_Incep3_3, name="cmp3" ) %>%
              add_histogram(x = ~pca_Incep3_4, name="cmp4" ) %>%
                add_histogram(x = ~pca_Incep3_5, name="cmp5" ) %>%
                    add_histogram(x = ~pca_Incep3_6, name="cmp6" ) %>%
                      add_histogram(x = ~pca_Incep3_7, name="cmp7" ) %>%
                           add_histogram(x = ~pca_Incep3_8, name="cmp8" ) %>%
                                add_histogram(x = ~pca_Incep3_9, name="cmp9" ) %>%
                                     add_histogram(x = ~pca_Incep3_10, name="cmp10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "Incep3_outputs")

Inceptrain[1:5,1:5]
Inceptest[1:5,1:5]

VGG19 Net

### REMOVE NEAR ZERO VARIATION
nzv_11<- nearZeroVar(RN50train)
nzv_12<- nearZeroVar(RN50test)
if(length(unique(c(nzv_11,nzv_12)))>0)
      {
        RN50train<- RN50train[, -unique(c(nzv_11,nzv_12))]
        RN50train<- RN50test[, -unique(c(nzv_11,nzv_12))]
        }
##Check consistency at both sets
head(cbind(train.mean = lapply(RN50train[,-1], mean),
          train.sd = lapply(RN50train[,-1], sd),
                test.mean = lapply(RN50test[,-1], mean),
                      test.sd = lapply(RN50test[,-1], sd)))
   train.mean   train.sd    test.mean    test.sd     
X0 0.0001554248 0.001995509 6.449305e-05 0.0002435841
X1 0.0003164812 0.001406066 0.0002199558 0.0004748997
X2 0.01424675   0.07969592  0.01391735   0.08040511  
X3 0.004219607  0.0270677   0.002187854  0.01284288  
X4 0.0001869516 0.002081979 0.0002245818 0.002877667 
X5 0.001481098  0.005702296 0.002190592  0.01193404  
#### Plot first
RN50train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~X0, name="X0") %>%
          add_histogram(x = ~X1,name="X1" ) %>%
           add_histogram(x = ~X2, name="X2" ) %>%
              add_histogram(x = ~X3, name="X3" ) %>%
                add_histogram(x = ~X4, name="X4" ) %>%
                    add_histogram(x = ~X5, name="X5" ) %>%
                      add_histogram(x = ~X6, name="X6" ) %>%
                           add_histogram(x = ~X7, name="X7" ) %>%
                                add_histogram(x = ~X8, name="X8" ) %>%
                                     add_histogram(x = ~X9, name="X9" ) %>%
                                        add_histogram(x = ~X10, name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "RN50train_outputs")

#### Plot log
RN50train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~log(X0), name="X0") %>%
          add_histogram(x = ~log(X1),name="X1" ) %>%
           add_histogram(x = ~log(X2), name="X2" ) %>%
              add_histogram(x = ~log(X3), name="X3" ) %>%
                add_histogram(x = ~log(X4), name="X4" ) %>%
                    add_histogram(x = ~log(X5), name="X5" ) %>%
                      add_histogram(x = ~log(X6), name="X6" ) %>%
                           add_histogram(x = ~log(X7), name="X7" ) %>%
                                add_histogram(x = ~log(X8), name="X8" ) %>%
                                     add_histogram(x = ~log(X9), name="X9" ) %>%
                                        add_histogram(x = ~log(X10), name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "log(RN50train_outputs)")

####################################################################################################
####################################################################################################
# conduct PCA on training dataset
num.cols <- names(which(sapply( RN50train, function(x) is.numeric(x) )))
pca <- prcomp(RN50train[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)
### Plot importance
p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                    geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~RN50train features ")
ggplotly(p)

####################################################################################################
####################################################################################################
####################################################################################################
#Replace features by PCA components
RN50train_pca<-as.data.frame(pca$x[,1:40])
colnames(RN50train_pca)<-paste("pca_RN50_",1:40,sep="")
### APPLY TO TESTING DATA 
RN50test_pca<-as.data.frame(predict(pca, newdata=RN50test[,num.cols])[,1:40])
colnames(RN50test_pca)<-paste("pca_RN50_",1:40,sep="")
RN50train<-cbind(RN50train[,1],RN50train_pca)
RN50test<-cbind(RN50test[,1],RN50test_pca)
colnames(RN50train)[1]<-colnames(RN50test)[1]<-"image_name"
RN50train<-left_join(trainCat,RN50train, by=c("image_name"="image_name"))
#### Plot Four first dimensions
p <- plot_ly(RN50train, x = ~pca_RN50_1, y = ~pca_RN50_2, color = ~as.factor(type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))
p

#### Plot first
RN50train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~pca_RN50_1, name="cmp1") %>%
          add_histogram(x = ~pca_RN50_2,name="cmp2" ) %>%
           add_histogram(x = ~pca_RN50_3, name="cmp3" ) %>%
              add_histogram(x = ~pca_RN50_4, name="cmp4" ) %>%
                add_histogram(x = ~pca_RN50_5, name="cmp5" ) %>%
                    add_histogram(x = ~pca_RN50_6, name="cmp6" ) %>%
                      add_histogram(x = ~pca_RN50_7, name="cmp7" ) %>%
                           add_histogram(x = ~pca_RN50_8, name="cmp8" ) %>%
                                add_histogram(x = ~pca_RN50_9, name="cmp9" ) %>%
                                     add_histogram(x = ~pca_RN50_10, name="cmp10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "RN50_outputs")

RN50train[1:5,1:5]
RN50test[1:5,1:5]

Generate outputs

### REMOVE NEAR ZERO VARIATION
nzv_11<- nearZeroVar(VGG19train)
nzv_12<- nearZeroVar(VGG19test)
if(length(unique(c(nzv_11,nzv_12)))>0)
      {
        VGG19train<- VGG19train[, -unique(c(nzv_11,nzv_12))]
        VGG19train<- VGG19test[, -unique(c(nzv_11,nzv_12))]
        }
##Check consistency at both sets
head(cbind(train.mean = lapply(VGG19train[,-1], mean),
          train.sd = lapply(VGG19train[,-1], sd),
                test.mean = lapply(VGG19test[,-1], mean),
                      test.sd = lapply(VGG19test[,-1], sd)))
   train.mean   train.sd     test.mean    test.sd     
X0 0.000152056  0.0009286555 0.0001250537 0.0005295175
X1 0.002372518  0.007802148  0.003164084  0.01971411  
X2 0.001756746  0.008479258  0.001684431  0.006802914 
X3 0.002490829  0.01408015   0.001586751  0.006244418 
X4 0.0007154238 0.002576961  0.0004852541 0.0009564264
X5 0.0007731305 0.002517532  0.0007732334 0.002002366 
#### Plot first
VGG19train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~X0, name="X0") %>%
          add_histogram(x = ~X1,name="X1" ) %>%
           add_histogram(x = ~X2, name="X2" ) %>%
              add_histogram(x = ~X3, name="X3" ) %>%
                add_histogram(x = ~X4, name="X4" ) %>%
                    add_histogram(x = ~X5, name="X5" ) %>%
                      add_histogram(x = ~X6, name="X6" ) %>%
                           add_histogram(x = ~X7, name="X7" ) %>%
                                add_histogram(x = ~X8, name="X8" ) %>%
                                     add_histogram(x = ~X9, name="X9" ) %>%
                                        add_histogram(x = ~X10, name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "VGG19train_outputs")

#### Plot log
VGG19train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~log(X0), name="X0") %>%
          add_histogram(x = ~log(X1),name="X1" ) %>%
           add_histogram(x = ~log(X2), name="X2" ) %>%
              add_histogram(x = ~log(X3), name="X3" ) %>%
                add_histogram(x = ~log(X4), name="X4" ) %>%
                    add_histogram(x = ~log(X5), name="X5" ) %>%
                      add_histogram(x = ~log(X6), name="X6" ) %>%
                           add_histogram(x = ~log(X7), name="X7" ) %>%
                                add_histogram(x = ~log(X8), name="X8" ) %>%
                                     add_histogram(x = ~log(X9), name="X9" ) %>%
                                        add_histogram(x = ~log(X10), name="X10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "log(VGG19train_outputs)")

####################################################################################################
####################################################################################################
# conduct PCA on training dataset
num.cols <- names(which(sapply( VGG19train, function(x) is.numeric(x) )))
pca <- prcomp(VGG19train[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)
### Plot importance
p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                    geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~VGG19train features ")
ggplotly(p)

####################################################################################################
####################################################################################################
####################################################################################################
#Replace features by PCA components
VGG19train_pca<-as.data.frame(pca$x[,1:40])
colnames(VGG19train_pca)<-paste("pca_VGG19_",1:40,sep="")
### APPLY TO TESTING DATA 
VGG19test_pca<-as.data.frame(predict(pca, newdata=VGG19test[,num.cols])[,1:40])
colnames(VGG19test_pca)<-paste("pca_VGG19_",1:40,sep="")
VGG19train<-cbind(VGG19train[,1],VGG19train_pca)
VGG19test<-cbind(VGG19test[,1],VGG19test_pca)
colnames(VGG19train)[1]<-colnames(VGG19test)[1]<-"image_name"
VGG19train<-left_join(trainCat,VGG19train, by=c("image_name"="image_name"))
#### Plot Four first dimensions
p <- plot_ly(VGG19train, x = ~pca_VGG19_1, y = ~pca_VGG19_2, color = ~as.factor(type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))
p

#### Plot first
VGG19train%>%
    plot_ly(alpha = 0.6) %>%
        add_histogram(x = ~pca_VGG19_1, name="cmp1") %>%
          add_histogram(x = ~pca_VGG19_2,name="cmp2" ) %>%
           add_histogram(x = ~pca_VGG19_3, name="cmp3" ) %>%
              add_histogram(x = ~pca_VGG19_4, name="cmp4" ) %>%
                add_histogram(x = ~pca_VGG19_5, name="cmp5" ) %>%
                    add_histogram(x = ~pca_VGG19_6, name="cmp6" ) %>%
                      add_histogram(x = ~pca_VGG19_7, name="cmp7" ) %>%
                           add_histogram(x = ~pca_VGG19_8, name="cmp8" ) %>%
                                add_histogram(x = ~pca_VGG19_9, name="cmp9" ) %>%
                                     add_histogram(x = ~pca_VGG19_10, name="cmp10" ) %>%
                                        layout(barmode = "overlay",
                                               title = "VGG19_outputs")

VGG19train[1:5,1:5]
VGG19test[1:5,1:5]

correlation ~rest features

write.csv(train_,"train_v1.csv",row.names = FALSE )
Error in is.data.frame(x) : object 'train_' not found


#scale train
feat_X3D_train_s<- scale(as.matrix(feat_X3D_train), center=TRUE,scale=TRUE)

#scale testing
feat_X3D_test_s<- scale(as.matrix(feat_X3D_test),
                         attr(feat_X3D_train_s, "scaled:center"),
                                        attr(feat_X3D_train_s, "scaled:scale") )


##Transform both sets
feat_X3D_train<-as.data.frame(feat_X3D_train_s[,])
feat_X3D_test<-as.data.frame(feat_X3D_test_s[,])

## Check
feat_X3D_train[1:5,1:5]
feat_X3D_test[1:5,1:5]
# 
# #to data frame
# feat_X3D_train_s<-as.data.frame(feat_X3D_train_s)
#     feat_X3D_test_s<-as.data.frame(feat_X3D_test_s)
# 
# 
# ##############################################3
# rep_X3D<-cbind(train.mean = lapply(feat_X3D_train_s[,-1], mean),
#                      train.sd = lapply(feat_X3D_train_s[,-1], sd),
#                            test.mean = lapply(feat_X3D_test_s[,-1], mean),
#                                 test.sd = lapply(feat_X3D_test_s[,-1], sd))
# head(rep_X3D)
# 
# 
# ##############################################3
# 
# 
# ### check in detail
# library(xda)
# xdatrain<-numSummary(feat_X3D_train_s)
# head(xdatrain)
# xdatest<-numSummary(feat_X3D_test_s)
# head(xdatest)
#xdatab2<-cha

#scale train
feat_pixel_train_s<- scale(as.matrix(feat_pixel_train), center=TRUE,scale=TRUE)

#scale testing
feat_pixel_test_s<- scale(as.matrix(feat_pixel_test),
                         attr(feat_pixel_train_s, "scaled:center"),
                                        attr(feat_pixel_train_s, "scaled:scale") )

##Transform both sets
feat_pixel_train<-as.data.frame(feat_pixel_train_s[,])
feat_pixel_test<-as.data.frame(feat_pixel_test_s[,])

## Check
feat_pixel_train[1:5,1:5]
feat_pixel_test[1:5,1:5]

# 
# 
# 
# #to data frame
# feat_pixel_train_s<-as.data.frame(feat_pixel_train_s)
#     feat_pixel_test_s<-as.data.frame(feat_pixel_test_s)
# 
# 
# ##############################################3
# rep_pixel<-cbind(train.mean = lapply(feat_pixel_train_s[,-1], mean),
#                      train.sd = lapply(feat_pixel_train_s[,-1], sd),
#                            test.mean = lapply(feat_pixel_test_s[,-1], mean),
#                                 test.sd = lapply(feat_pixel_test_s[,-1], sd))
# head(rep_pixel)
# 
# 
# ##############################################3
# 
# 
# ### check in detail
# library(xda)
# xdatrain<-numSummary(feat_pixel_train_s)
# head(xdatrain)
# xdatest<-numSummary(feat_pixel_test_s)
# head(xdatest)
# #xdatab2<-cha

correlation ~pixel features

####################################################################################################################
#Elegimos las componentes a utilizar
num.cols <- names(which(sapply(feat_pixel_train, function(x) is.numeric(x) )))

set.seed(1234)
num.cols<- sample(num.cols, 100)

svd_seq<-feat_pixel_train[,num.cols ]
# Correlation scatter plots for all combinations between the first four principal components.
library(reshape2)
cormat <- round(cor(svd_seq),4)
melted_cormat <- melt(cormat)
head(melted_cormat)


p<-ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) + 
  geom_tile()
ggplotly(p)

PCA from ~pixel features


# conduct PCA on training dataset
num.cols <- names(which(sapply(feat_pixel_train, function(x) is.numeric(x) )))

pca <- prcomp(feat_pixel_train[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)

p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                    geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~pixel features ")
ggplotly(p)
#Replace features by PCA components
feat_pixel_train_pca<-as.data.frame(pca$x[,1:100])
colnames(feat_pixel_train_pca)<-paste("pca_pixel_",1:100,sep="")

### APPLY TO TESTING DATA 
feat_pixel_test_pca<-as.data.frame(predict(pca, newdata=feat_pixel_test[,num.cols])[,1:100])
colnames(feat_pixel_test_pca)<-paste("pca_pixel_",1:100,sep="")

scatter first 4 dimensions


library(plotly)

pc<-as.data.frame(pca$x[,1:4])%>%
                      rename(Dim1=PC1,
                             Dim2=PC2,
                             Dim3=PC3,
                             Dim4=PC4)

p <- plot_ly(pc, x = ~Dim1, y = ~Dim2, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))

p

p <- plot_ly(pc, x = ~Dim1, y = ~Dim3, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim3')))

p

p <- plot_ly(pc, x = ~Dim2, y = ~Dim4, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim4')))

p

correlation ~X3D features

####################################################################################################################
#Elegimos las componentes a utilizar
num.cols <- names(which(sapply(feat_X3D_train, function(x) is.numeric(x) )))

svd_seq<-feat_X3D_train[,num.cols ]
# Correlation scatter plots for all combinations between the first four principal components.
library(reshape2)
cormat <- round(cor(svd_seq),4)
melted_cormat <- melt(cormat)
head(melted_cormat)


p<-ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) + 
  geom_tile()
ggplotly(p)

PCA from ~X3D features


# conduct PCA on training dataset
num.cols <- names(which(sapply(feat_X3D_train, function(x) is.numeric(x) )))

pca <- prcomp(feat_X3D_train[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)

p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                                            geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~X3D features ")
ggplotly(p)
#Replace features by PCA components
feat_X3D_train_pca<-as.data.frame(pca$x[,1:10])
colnames(feat_X3D_train_pca)<-paste("pca_X3D_",1:10,sep="")

### Apply to testing
feat_X3D_test_pca<-as.data.frame(predict(pca, newdata=feat_X3D_test[,num.cols])[,1:10])
colnames(feat_X3D_test_pca)<-paste("pca_X3D_",1:10,sep="")

scatter first 4 dimensions


library(plotly)

pc<-as.data.frame(pca$x[,1:4])%>%
                      rename(Dim1=PC1,
                             Dim2=PC2,
                             Dim3=PC3,
                             Dim4=PC4)

p <- plot_ly(pc, x = ~Dim1, y = ~Dim2, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))

p

p <- plot_ly(pc, x = ~Dim1, y = ~Dim3, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim3')))

p

p <- plot_ly(pc, x = ~Dim2, y = ~Dim4, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim4')))

p

Análisis de correlación

####################################################################################################################
#Elegimos las componentes a utilizar
num.cols <- names(which(sapply(feat_rest_train, function(x) is.numeric(x) )))

svd_seq<-feat_rest_train[,num.cols ]
# Correlation scatter plots for all combinations between the first four principal components.
library(reshape2)
cormat <- round(cor(svd_seq),4)
melted_cormat <- melt(cormat)
head(melted_cormat)


p<-ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) + 
  geom_tile()
ggplotly(p)

PCA from ~rest features


# conduct PCA on training dataset
num.cols <- names(which(sapply(feat_rest_train, function(x) is.numeric(x) )))

pca <- prcomp(feat_rest_train[,num.cols], retx=TRUE, center=FALSE, scale=FALSE)
#Eigenvalues
eig <- (pca$sdev)^2 ; variance <-eig*100/sum(eig) ; cumvar <- cumsum(variance) ; Comp<- 1:length(cumvar)

p<-as.data.frame(cbind(Comp,cumvar)) %>%
                ggplot(aes(x =factor(Comp), y = cumvar)) + 
                                            geom_bar(stat = "identity")  + geom_hline(yintercept=95, col="red") +
                            xlab("components  ~X3D features ")
ggplotly(p)
#Replace features by PCA components
feat_rest_train_pca<-as.data.frame(pca$x[,1:12])
colnames(feat_rest_train_pca)<-paste("pca_rest_",1:12,sep="")

## Apply to testing
feat_rest_test_pca<-as.data.frame(predict(pca, newdata=feat_rest_test[,num.cols])[,1:12])
colnames(feat_rest_test_pca)<-paste("pca_rest_",1:12,sep="")

scatter first 4 dimensions


library(plotly)

pc<-as.data.frame(pca$x[,1:4])%>%
                      rename(Dim1=PC1,
                             Dim2=PC2,
                             Dim3=PC3,
                             Dim4=PC4)

p <- plot_ly(pc, x = ~Dim1, y = ~Dim2, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim2')))

p

p <- plot_ly(pc, x = ~Dim1, y = ~Dim3, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim3')))

p

p <- plot_ly(pc, x = ~Dim2, y = ~Dim4, color = ~as.factor(train_index$type_cat)) %>%
  layout(scene = list(xaxis = list(title = 'Dim1'),
                     yaxis = list(title = 'Dim4')))

p

Análisis de correlación X3D + PCA

testcor<-cbind(feat_X3D_train_pca, feat_X3D_train)

svd_seq<-testcor
# Correlation scatter plots for all combinations between the first four principal components.
library(reshape2)
cormat <- round(cor(svd_seq),4)
melted_cormat <- melt(cormat)
head(melted_cormat)


p<-ggplot(data = melted_cormat, aes(x=Var1, y=Var2, fill=value)) + 
  geom_tile()
ggplotly(p)


#feat_X3D_train_pca, feat_X3D_train, feat_pixel_train_pca,feat_rest_train_pca
LS0tCnRpdGxlOiAiVMOpY25pY2FzIGRlICBjbHVzdGVyaW5nIGFwbGljYWRvIGFsIGVzdHVkaW8gZGUgdmFyaWFudGVzIGRlIGdlbm9tYXMgdmlyYWxlcyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfd2lkdGg6IDEwCi0tLQoKCgpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgc2V0dXB9CiNsaWJyZXJpYXMgbmVjZXNhcmlhcwoKCiNsaWJyYXJ5IChCaW9zdHJpbmdzKSAjIE1hbmlwdWxhY2lvbiBkZSBzZWN1ZW5jaWFzIHkgYWxpbmVhbWllbnRvcwoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSAoUkNvbG9yQnJld2VyKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRwbHlyKQojbGlicmFyeShyZXNoYXBlMikKbGlicmFyeShwc3ljaCkKbGlicmFyeShpcmxiYSkKbGlicmFyeShmcGMpCgpgYGAKCgoKIyMjIERhdGEKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgfQp0cmFpbl92MTwtcmVhZC5jc3YoImNjcy5uZXdfdHJhaW5fdjEuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSU+JXNlbGVjdCgtaWQpCnRyYWluQ2F0PC10cmFpbl92MSU+JXNlbGVjdCh0eXBlX2NhdCwgaW1hZ2VfbmFtZSkKdGVzdF92MTwtcmVhZC5jc3YoImNjcy5uZXdfdGVzdF92MS5jc3YiICwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSU+JXNlbGVjdCgtaWQpCgpgYGAKCgoKIyMjIE5TRlcKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgfQpOU0ZXdHJhaW48LXJlYWQuY3N2KCJuc2Z3T3V0X3RyYWluLmNzdiIgLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGhlYWRlcj1GQUxTRSklPiUKICAgICAgICAgICAgICAgIHJlbmFtZShpbWFnZV9uYW1lPVYxLCBuc2Z3X3ZhbD1WMiklPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUobnNmd192YWxfbG9nPWxvZyhuc2Z3X3ZhbCkpCk5TRld0ZXN0PC1yZWFkLmNzdigibnNmd091dF90ZXN0LmNzdiIgLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGhlYWRlcj1GQUxTRSklPiUKICAKICAgICAgICAgICAgICAgIHJlbmFtZShpbWFnZV9uYW1lPVYxLCBuc2Z3X3ZhbD1WMiklPiUKICAgICAgICAgICAgICAgICAgICBtdXRhdGUobnNmd192YWxfbG9nPWxvZyhuc2Z3X3ZhbCkpCgoKCgpOU0ZXdHJhaW48LWxlZnRfam9pbih0cmFpbkNhdCxOU0ZXdHJhaW4sIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikpCgpOU0ZXdHJhaW4lPiUKICBzcHJlYWQodHlwZV9jYXQsIG5zZndfdmFsKSU+JQogICAgcGxvdF9seShhbHBoYSA9IDAuNikgJT4lCiAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflR5cGVfMSwgbmFtZT0iVHlwZV8xIikgJT4lCiAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+VHlwZV8yLG5hbWU9IlR5cGVfMiIgKSAlPiUKICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+VHlwZV8zLCBuYW1lPSJUeXBlXzMiICkgJT4lCiAgICAgICAgbGF5b3V0KGJhcm1vZGUgPSAib3ZlcmxheSIsdGl0bGUgPSAiTlNGVyB2YWx1ZSIpCgojIyBMb2dhcml0bWljCk5TRld0cmFpbiU+JQogIHNwcmVhZCh0eXBlX2NhdCwgbnNmd192YWwpJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFR5cGVfMSksIG5hbWU9IlR5cGVfMSIpICU+JQogICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhUeXBlXzIpLG5hbWU9IlR5cGVfMiIgKSAlPiUKICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFR5cGVfMyksIG5hbWU9IlR5cGVfMyIgKSAlPiUKICAgICAgICBsYXlvdXQoYmFybW9kZSA9ICJvdmVybGF5IiwgdGl0bGUgPSAibG9nKE5TRlcgdmFsdWUpIikKCgojI0NoZWNrIGNvbnNpc3RlbmN5IGF0IGJvdGggc2V0cwpoZWFkKGNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoTlNGV3RyYWluJT4lc2VsZWN0KG5zZndfdmFsLG5zZndfdmFsX2xvZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXttZWFuKHgsbmEucm09VFJVRSl9ICksCiAgICAgICAgICAgICAgdHJhaW4uc2QgPSBsYXBwbHkoTlNGV3RyYWluJT4lc2VsZWN0KG5zZndfdmFsLG5zZndfdmFsX2xvZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXtzZCh4LG5hLnJtPVRSVUUpfSApLAogICAgICAgICAgICAgICAgIHRlc3QubWVhbiA9IGxhcHBseShOU0ZXdGVzdCU+JXNlbGVjdChuc2Z3X3ZhbCxuc2Z3X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpe21lYW4oeCxuYS5ybT1UUlVFKX0pLAogICAgICAgICAgICAgICAgICAgICAgdGVzdC5zZCA9IGxhcHBseShOU0ZXdGVzdCU+JXNlbGVjdChuc2Z3X3ZhbCxuc2Z3X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXtzZCh4LG5hLnJtPVRSVUUpfSkpKQoKCgpgYGAKCgoKCiMjIyBEaXN0YW5jZQpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSB9CkRpc3RyYWluPC1yZWFkLmNzdigidHJhaW5fZGlzdGFuY2UuY3N2IiAsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGhlYWRlcj1GQUxTRSklPiUKICAgICAgICAgICAgICAgICAgICAgcmVuYW1lKGltYWdlX25hbWU9VjEsIGRpc3RfdmFsPVYyKSU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGlzdF92YWxfbG9nPWxvZyhkaXN0X3ZhbCkpCiAgCkRpc3Rlc3Q8LXJlYWQuY3N2KCJ0ZXN0X2Rpc3RhbmNlLmNzdiIgLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgIGhlYWRlcj1GQUxTRSklPiUKICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZShpbWFnZV9uYW1lPVYxLCBkaXN0X3ZhbD1WMiklPiUKICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZGlzdF92YWxfbG9nPWxvZyhkaXN0X3ZhbCkpCgpEaXN0cmFpbjwtbGVmdF9qb2luKHRyYWluQ2F0LERpc3RyYWluLCBieT1jKCJpbWFnZV9uYW1lIj0iaW1hZ2VfbmFtZSIpKQoKCiMjQ2hlY2sgY29uc2lzdGVuY3kgYXQgYm90aCBzZXRzCmhlYWQoY2JpbmQodHJhaW4ubWVhbiA9IGxhcHBseShEaXN0cmFpbiU+JXNlbGVjdChkaXN0X3ZhbCxkaXN0X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCl7bWVhbih4LG5hLnJtPVRSVUUpfSApLAogICAgICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KERpc3RyYWluJT4lc2VsZWN0KGRpc3RfdmFsLGRpc3RfdmFsX2xvZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KXtzZCh4LG5hLnJtPVRSVUUpfSApLAogICAgICAgICAgICAgICAgIHRlc3QubWVhbiA9IGxhcHBseShEaXN0ZXN0JT4lc2VsZWN0KGRpc3RfdmFsLGRpc3RfdmFsX2xvZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCl7bWVhbih4LG5hLnJtPVRSVUUpfSksCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnNkID0gbGFwcGx5KERpc3Rlc3QlPiVzZWxlY3QoZGlzdF92YWwsZGlzdF92YWxfbG9nKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCl7c2QoeCxuYS5ybT1UUlVFKX0pKSkKCgoKI3NjYWxlIHRyYWluCkRpc3RyYWluX3M8LSBzY2FsZShhcy5tYXRyaXgoRGlzdHJhaW4lPiVzZWxlY3QoZGlzdF92YWwsIGRpc3RfdmFsX2xvZykpLAogICAgICAgICAgICAgICAgICAgY2VudGVyPVRSVUUsc2NhbGU9VFJVRSkKCiNzY2FsZSB0ZXN0aW5nCkRpc3Rlc3RfczwtIHNjYWxlKGFzLm1hdHJpeChEaXN0ZXN0JT4lc2VsZWN0KGRpc3RfdmFsLCBkaXN0X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIoRGlzdHJhaW5fcywgInNjYWxlZDpjZW50ZXIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0cihEaXN0cmFpbl9zLCAic2NhbGVkOnNjYWxlIikgKSApCgoKIyNUcmFuc2Zvcm0gYm90aCBzZXRzCkRpc3RyYWluPC1jYmluZChEaXN0cmFpbiU+JXNlbGVjdCh0eXBlX2NhdCwgaW1hZ2VfbmFtZSkgLCBEaXN0cmFpbl9zWyxdKQpEaXN0ZXN0PC1jYmluZChEaXN0ZXN0JT4lc2VsZWN0KCBpbWFnZV9uYW1lKSAsIERpc3Rlc3Rfc1ssXSkKCgoKCkRpc3RyYWluJT4lCiAgc3ByZWFkKHR5cGVfY2F0LCBkaXN0X3ZhbCklPiUKICAgIHBsb3RfbHkoYWxwaGEgPSAwLjYpICU+JQogICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5UeXBlXzEsIG5hbWU9IlR5cGVfMSIpICU+JQogICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflR5cGVfMixuYW1lPSJUeXBlXzIiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflR5cGVfMywgbmFtZT0iVHlwZV8zIiApICU+JQogICAgICAgIGxheW91dChiYXJtb2RlID0gIm92ZXJsYXkiLAogICAgICAgICAgICAgICB0aXRsZSA9ICJEaXN0YW5jZSIpCgojIyMgTG9nYXJpdG0KRGlzdHJhaW4lPiUKICBzcHJlYWQodHlwZV9jYXQsIGRpc3RfdmFsKSU+JQogICAgcGxvdF9seShhbHBoYSA9IDAuNikgJT4lCiAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhUeXBlXzEpLCBuYW1lPSJUeXBlXzEiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coVHlwZV8yKSxuYW1lPSJUeXBlXzIiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhUeXBlXzMpLCBuYW1lPSJUeXBlXzMiICkgJT4lCiAgICAgICAgbGF5b3V0KGJhcm1vZGUgPSAib3ZlcmxheSIsCiAgICAgICAgICAgICAgIHRpdGxlID0gIkxvZyAoRGlzdGFuY2UpIikKCgojIyBDaGVjawpEaXN0cmFpblsxOjUsMTo0XQpEaXN0ZXN0WzE6NSwxOjNdCgojI0NoZWNrIGNvbnNpc3RlbmN5IGF0IGJvdGggc2V0cwpoZWFkKGNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoRGlzdHJhaW4lPiVzZWxlY3QoZGlzdF92YWwsZGlzdF92YWxfbG9nKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpe21lYW4oeCxuYS5ybT1UUlVFKX0gKSwKICAgICAgICAgICAgICB0cmFpbi5zZCA9IGxhcHBseShEaXN0cmFpbiU+JXNlbGVjdChkaXN0X3ZhbCxkaXN0X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCl7c2QoeCxuYS5ybT1UUlVFKX0gKSwKICAgICAgICAgICAgICAgICB0ZXN0Lm1lYW4gPSBsYXBwbHkoRGlzdGVzdCU+JXNlbGVjdChkaXN0X3ZhbCxkaXN0X3ZhbF9sb2cpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpe21lYW4oeCxuYS5ybT1UUlVFKX0pLAogICAgICAgICAgICAgICAgICAgICAgdGVzdC5zZCA9IGxhcHBseShEaXN0ZXN0JT4lc2VsZWN0KGRpc3RfdmFsLGRpc3RfdmFsX2xvZyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpe3NkKHgsbmEucm09VFJVRSl9KSkpCgoKYGBgCgoKCgoKCiMjIyBoYXNoaW5nCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFIH0KcEhhc2h0cmFpbjwtcmVhZC5jc3YoImhhc2hlc18xNl9waGFzaF90cmFpbmluZy5jc3YiICwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBoZWFkZXI9RkFMU0UpJT4lc2VsZWN0KC1WMiklPiUKICAgICAgICAgICNtdXRhdGVfZWFjaChmdW5zKHdoYXRldmVyID0gLi8xNSksIFYzOlY2NikKICAgICAgICAgICAgbXV0YXRlX2VhY2goZnVucyguLzE1KSwgVjM6VjY2KQpwSGFzaHRlc3Q8LXJlYWQuY3N2KCJoYXNoZXNfMTZfcGhhc2hfdGVzdGluZy5jc3YiICwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCBoZWFkZXI9RkFMU0UpJT4lc2VsZWN0KC1WMiklPiUKICAgICAgICAgIG11dGF0ZV9lYWNoKGZ1bnMoLi8xNSksIFYzOlY2NikKCgoKIyMjIFJFTU9WRSBORUFSIFpFUk8gVkFSSUFUSU9OCm56dl8xMTwtIG5lYXJaZXJvVmFyKHBIYXNodHJhaW4pCm56dl8xMjwtIG5lYXJaZXJvVmFyKHBIYXNodGVzdCkKaWYobGVuZ3RoKHVuaXF1ZShjKG56dl8xMSxuenZfMTIpKSk+MCkKICAgICAgewogICAgICAgIHBIYXNodHJhaW48LSBwSGFzaHRyYWluWywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICBwSGFzaHRlc3Q8LSBwSGFzaHRlc3RbLCAtdW5pcXVlKGMobnp2XzExLG56dl8xMikpXQogICAgICAgIH0KCiMjQ2hlY2sgY29uc2lzdGVuY3kgYXQgYm90aCBzZXRzCmhlYWQoY2JpbmQodHJhaW4ubWVhbiA9IGxhcHBseShwSGFzaHRyYWluWywtMV0sIG1lYW4pLAogICAgICAgICAgdHJhaW4uc2QgPSBsYXBwbHkocEhhc2h0cmFpblssLTFdLCBzZCksCiAgICAgICAgICAgICAgICB0ZXN0Lm1lYW4gPSBsYXBwbHkocEhhc2h0ZXN0WywtMV0sIG1lYW4pLAogICAgICAgICAgICAgICAgICAgICAgdGVzdC5zZCA9IGxhcHBseShwSGFzaHRlc3RbLC0xXSwgc2QpKSkKCgoKIyBjb25kdWN0IFBDQSBvbiB0cmFpbmluZyBkYXRhc2V0Cm51bS5jb2xzIDwtIG5hbWVzKHdoaWNoKHNhcHBseSggcEhhc2h0cmFpbiwgZnVuY3Rpb24oeCkgaXMubnVtZXJpYyh4KSApKSkKCnBjYSA8LSBwcmNvbXAocEhhc2h0cmFpblssbnVtLmNvbHNdLCByZXR4PVRSVUUsIGNlbnRlcj1GQUxTRSwgc2NhbGU9RkFMU0UpCiNFaWdlbnZhbHVlcwplaWcgPC0gKHBjYSRzZGV2KV4yIDsgdmFyaWFuY2UgPC1laWcqMTAwL3N1bShlaWcpIDsgY3VtdmFyIDwtIGN1bXN1bSh2YXJpYW5jZSkgOyBDb21wPC0gMTpsZW5ndGgoY3VtdmFyKQoKCgojIyMgUGxvdCBpbXBvcnRhbmNlCgpwPC1hcy5kYXRhLmZyYW1lKGNiaW5kKENvbXAsY3VtdmFyKSkgJT4lCiAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHggPWZhY3RvcihDb21wKSwgeSA9IGN1bXZhcikpICsgCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICArIGdlb21faGxpbmUoeWludGVyY2VwdD05NSwgY29sPSJyZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJjb21wb25lbnRzICB+cGl4ZWwgZmVhdHVyZXMgIikKZ2dwbG90bHkocCkKCgoKCgojUmVwbGFjZSBmZWF0dXJlcyBieSBQQ0EgY29tcG9uZW50cwpwSGFzaHRyYWluX3BjYTwtYXMuZGF0YS5mcmFtZShwY2EkeFssMTo0MF0pCmNvbG5hbWVzKHBIYXNodHJhaW5fcGNhKTwtcGFzdGUoInBjYV9wSGFzaF8iLDE6NDAsc2VwPSIiKQoKIyMjIEFQUExZIFRPIFRFU1RJTkcgREFUQSAKcEhhc2h0ZXN0X3BjYTwtYXMuZGF0YS5mcmFtZShwcmVkaWN0KHBjYSwgbmV3ZGF0YT1wSGFzaHRlc3RbLG51bS5jb2xzXSlbLDE6NDBdKQpjb2xuYW1lcyhwSGFzaHRlc3RfcGNhKTwtcGFzdGUoInBjYV9wSGFzaF8iLDE6NDAsc2VwPSIiKQoKCnBIYXNodHJhaW48LWNiaW5kKHBIYXNodHJhaW5bLDFdLHBIYXNodHJhaW5fcGNhKQoKcEhhc2h0ZXN0PC1jYmluZChwSGFzaHRlc3RbLDFdLHBIYXNodGVzdF9wY2EpCmNvbG5hbWVzKHBIYXNodHJhaW4pWzFdPC1jb2xuYW1lcyhwSGFzaHRlc3QpWzFdPC0iaW1hZ2VfbmFtZSIKcEhhc2h0cmFpbjwtbGVmdF9qb2luKHRyYWluQ2F0LHBIYXNodHJhaW4sIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikpCgoKIyMjIyBQbG90IEZvdXIgZmlyc3QgZGltZW5zaW9ucwpwIDwtIHBsb3RfbHkocEhhc2h0cmFpbiwgeCA9IH5wY2FfcEhhc2hfMSwgeSA9IH5wY2FfcEhhc2hfMiwgY29sb3IgPSB+YXMuZmFjdG9yKHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMicpKSkKCnAKCnBIYXNodHJhaW5bMTo1LDE6NV0KcEhhc2h0ZXN0WzE6NSwxOjVdCgpgYGAKCgoKIyMjIE5ldHdvcmtzCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFIH0KTmFtZXN0cmFpbjwtcmVhZC5jc3YoIk5hbWVzX3RyYWluX2ZlYXR1cmVzLmNzdiIgLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCk5hbWVzdGVzdDwtcmVhZC5jc3YoIk5hbWVzX3Rlc3RfZmVhdHVyZXMuY3N2IiAsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiMjIyMjIEluY2VwdGlvbnYzCkluY2VwdHJhaW48LSBjYmluZChOYW1lc3RyYWluLHJlYWQuY3N2KCJJbmNlcHRpb24zX3RyYWluX2ZlYXR1cmVzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgKQpJbmNlcHRlc3Q8LSBjYmluZChOYW1lc3Rlc3QsIHJlYWQuY3N2KCJJbmNlcHRpb24zX3Rlc3RfZmVhdHVyZXMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSApCgojIyMjIyBSZXNOZXQ1MApSTjUwdHJhaW48LWNiaW5kKE5hbWVzdHJhaW4sIHJlYWQuY3N2KCJSZXNOZXQ1MF90cmFpbl9mZWF0dXJlcy5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICkKUk41MHRlc3Q8LWNiaW5kKE5hbWVzdGVzdCAscmVhZC5jc3YoIlJlc05ldDUwX3Rlc3RfZmVhdHVyZXMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSApCgojIyMjI1ZHRzE5IApWR0cxOXRyYWluPC1jYmluZChOYW1lc3RyYWluICxyZWFkLmNzdigiVkdHMTlfdHJhaW5fZmVhdHVyZXMuY3N2IiAsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgKQpWR0cxOXRlc3Q8LWNiaW5kKE5hbWVzdGVzdCwgcmVhZC5jc3YoIlZHRzE5X3Rlc3RfZmVhdHVyZXMuY3N2IiAsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgKQoKYGBgCgoKCgoKIyMjIEluY2VwdGlvblYzIE5ldApgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSB9CgoKIyMjIFJFTU9WRSBORUFSIFpFUk8gVkFSSUFUSU9OCm56dl8xMTwtIG5lYXJaZXJvVmFyKEluY2VwdHJhaW4pCm56dl8xMjwtIG5lYXJaZXJvVmFyKEluY2VwdGVzdCkKaWYobGVuZ3RoKHVuaXF1ZShjKG56dl8xMSxuenZfMTIpKSk+MCkKICAgICAgewogICAgICAgIEluY2VwdHJhaW48LSBJbmNlcHRyYWluWywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICBJbmNlcHRyYWluPC0gSW5jZXB0ZXN0WywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICB9CgojI0NoZWNrIGNvbnNpc3RlbmN5IGF0IGJvdGggc2V0cwpoZWFkKGNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoSW5jZXB0cmFpblssLTFdLCBtZWFuKSwKICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KEluY2VwdHJhaW5bLC0xXSwgc2QpLAogICAgICAgICAgICAgICAgdGVzdC5tZWFuID0gbGFwcGx5KEluY2VwdGVzdFssLTFdLCBtZWFuKSwKICAgICAgICAgICAgICAgICAgICAgIHRlc3Quc2QgPSBsYXBwbHkoSW5jZXB0ZXN0WywtMV0sIHNkKSkpCgoKCiMjIyMgUGxvdCBmaXJzdApJbmNlcHRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDAsIG5hbWU9IlgwIikgJT4lCiAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDEsbmFtZT0iWDEiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflgyLCBuYW1lPSJYMiIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDMsIG5hbWU9IlgzIiApICU+JQogICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg0LCBuYW1lPSJYNCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDUsIG5hbWU9Ilg1IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg2LCBuYW1lPSJYNiIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg3LCBuYW1lPSJYNyIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDgsIG5hbWU9Ilg4IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg5LCBuYW1lPSJYOSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YMTAsIG5hbWU9IlgxMCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dChiYXJtb2RlID0gIm92ZXJsYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkluY2VwdHJhaW5fb3V0cHV0cyIpCgoKIyMjIyBQbG90IGxvZwpJbmNlcHRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgwKSwgbmFtZT0iWDAiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDEpLG5hbWU9IlgxIiApICU+JQogICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDIpLCBuYW1lPSJYMiIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgzKSwgbmFtZT0iWDMiICkgJT4lCiAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg0KSwgbmFtZT0iWDQiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNSksIG5hbWU9Ilg1IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNiksIG5hbWU9Ilg2IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg3KSwgbmFtZT0iWDciICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOCksIG5hbWU9Ilg4IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOSksIG5hbWU9Ilg5IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYMTApLCBuYW1lPSJYMTAiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQoYmFybW9kZSA9ICJvdmVybGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJsb2coSW5jZXB0cmFpbl9vdXRwdXRzKSIpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGNvbmR1Y3QgUENBIG9uIHRyYWluaW5nIGRhdGFzZXQKbnVtLmNvbHMgPC0gbmFtZXMod2hpY2goc2FwcGx5KCBJbmNlcHRyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKcGNhIDwtIHByY29tcChJbmNlcHRyYWluWyxudW0uY29sc10sIHJldHg9VFJVRSwgY2VudGVyPUZBTFNFLCBzY2FsZT1GQUxTRSkKI0VpZ2VudmFsdWVzCmVpZyA8LSAocGNhJHNkZXYpXjIgOyB2YXJpYW5jZSA8LWVpZyoxMDAvc3VtKGVpZykgOyBjdW12YXIgPC0gY3Vtc3VtKHZhcmlhbmNlKSA7IENvbXA8LSAxOmxlbmd0aChjdW12YXIpCgoKCiMjIyBQbG90IGltcG9ydGFuY2UKCnA8LWFzLmRhdGEuZnJhbWUoY2JpbmQoQ29tcCxjdW12YXIpKSAlPiUKICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeCA9ZmFjdG9yKENvbXApLCB5ID0gY3VtdmFyKSkgKyAKICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTk1LCBjb2w9InJlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoImNvbXBvbmVudHMgIH5JbmNlcHRyYWluIGZlYXR1cmVzICIpCmdncGxvdGx5KHApCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCgojUmVwbGFjZSBmZWF0dXJlcyBieSBQQ0EgY29tcG9uZW50cwpJbmNlcHRyYWluX3BjYTwtYXMuZGF0YS5mcmFtZShwY2EkeFssMTo1MF0pCmNvbG5hbWVzKEluY2VwdHJhaW5fcGNhKTwtcGFzdGUoInBjYV9JbmNlcDNfIiwxOjUwLHNlcD0iIikKCiMjIyBBUFBMWSBUTyBURVNUSU5HIERBVEEgCkluY2VwdGVzdF9wY2E8LWFzLmRhdGEuZnJhbWUocHJlZGljdChwY2EsIG5ld2RhdGE9SW5jZXB0ZXN0WyxudW0uY29sc10pWywxOjUwXSkKY29sbmFtZXMoSW5jZXB0ZXN0X3BjYSk8LXBhc3RlKCJwY2FfSW5jZXAzXyIsMTo1MCxzZXA9IiIpCgoKSW5jZXB0cmFpbjwtY2JpbmQoSW5jZXB0cmFpblssMV0sSW5jZXB0cmFpbl9wY2EpCkluY2VwdGVzdDwtY2JpbmQoSW5jZXB0ZXN0WywxXSxJbmNlcHRlc3RfcGNhKQoKY29sbmFtZXMoSW5jZXB0cmFpbilbMV08LWNvbG5hbWVzKEluY2VwdGVzdClbMV08LSJpbWFnZV9uYW1lIgpJbmNlcHRyYWluPC1sZWZ0X2pvaW4odHJhaW5DYXQsSW5jZXB0cmFpbiwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiKSkKCgojIyMjIFBsb3QgRm91ciBmaXJzdCBkaW1lbnNpb25zCnAgPC0gcGxvdF9seShJbmNlcHRyYWluLCB4ID0gfnBjYV9JbmNlcDNfMSwgeSA9IH5wY2FfSW5jZXAzXzIsIGNvbG9yID0gfmFzLmZhY3Rvcih0eXBlX2NhdCkpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTEnKSwKICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTInKSkpCgpwCgoKCiMjIyMgUGxvdCBmaXJzdApJbmNlcHRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX0luY2VwM18xLCBuYW1lPSJjbXAxIikgJT4lCiAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX0luY2VwM18yLG5hbWU9ImNtcDIiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9JbmNlcDNfMywgbmFtZT0iY21wMyIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX0luY2VwM180LCBuYW1lPSJjbXA0IiApICU+JQogICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9JbmNlcDNfNSwgbmFtZT0iY21wNSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX0luY2VwM182LCBuYW1lPSJjbXA2IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9JbmNlcDNfNywgbmFtZT0iY21wNyIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9JbmNlcDNfOCwgbmFtZT0iY21wOCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX0luY2VwM185LCBuYW1lPSJjbXA5IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9JbmNlcDNfMTAsIG5hbWU9ImNtcDEwIiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0KGJhcm1vZGUgPSAib3ZlcmxheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiSW5jZXAzX291dHB1dHMiKQoKCkluY2VwdHJhaW5bMTo1LDE6NV0KSW5jZXB0ZXN0WzE6NSwxOjVdCgpgYGAKCgoKCgoKCgoKCiMjIyBSZXNOZXQ1MCBOZXQKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgfQoKCiMjIyBSRU1PVkUgTkVBUiBaRVJPIFZBUklBVElPTgpuenZfMTE8LSBuZWFyWmVyb1ZhcihSTjUwdHJhaW4pCm56dl8xMjwtIG5lYXJaZXJvVmFyKFJONTB0ZXN0KQppZihsZW5ndGgodW5pcXVlKGMobnp2XzExLG56dl8xMikpKT4wKQogICAgICB7CiAgICAgICAgUk41MHRyYWluPC0gUk41MHRyYWluWywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICBSTjUwdHJhaW48LSBSTjUwdGVzdFssIC11bmlxdWUoYyhuenZfMTEsbnp2XzEyKSldCiAgICAgICAgfQoKIyNDaGVjayBjb25zaXN0ZW5jeSBhdCBib3RoIHNldHMKaGVhZChjYmluZCh0cmFpbi5tZWFuID0gbGFwcGx5KFJONTB0cmFpblssLTFdLCBtZWFuKSwKICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KFJONTB0cmFpblssLTFdLCBzZCksCiAgICAgICAgICAgICAgICB0ZXN0Lm1lYW4gPSBsYXBwbHkoUk41MHRlc3RbLC0xXSwgbWVhbiksCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0LnNkID0gbGFwcGx5KFJONTB0ZXN0WywtMV0sIHNkKSkpCgoKCiMjIyMgUGxvdCBmaXJzdApSTjUwdHJhaW4lPiUKICAgIHBsb3RfbHkoYWxwaGEgPSAwLjYpICU+JQogICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YMCwgbmFtZT0iWDAiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YMSxuYW1lPSJYMSIgKSAlPiUKICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDIsIG5hbWU9IlgyIiApICU+JQogICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YMywgbmFtZT0iWDMiICkgJT4lCiAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDQsIG5hbWU9Ilg0IiApICU+JQogICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YNSwgbmFtZT0iWDUiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDYsIG5hbWU9Ilg2IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDcsIG5hbWU9Ilg3IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YOCwgbmFtZT0iWDgiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDksIG5hbWU9Ilg5IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflgxMCwgbmFtZT0iWDEwIiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0KGJhcm1vZGUgPSAib3ZlcmxheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiUk41MHRyYWluX291dHB1dHMiKQoKCiMjIyMgUGxvdCBsb2cKUk41MHRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgwKSwgbmFtZT0iWDAiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDEpLG5hbWU9IlgxIiApICU+JQogICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDIpLCBuYW1lPSJYMiIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgzKSwgbmFtZT0iWDMiICkgJT4lCiAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg0KSwgbmFtZT0iWDQiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNSksIG5hbWU9Ilg1IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNiksIG5hbWU9Ilg2IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg3KSwgbmFtZT0iWDciICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOCksIG5hbWU9Ilg4IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOSksIG5hbWU9Ilg5IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYMTApLCBuYW1lPSJYMTAiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQoYmFybW9kZSA9ICJvdmVybGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJsb2coUk41MHRyYWluX291dHB1dHMpIikKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgY29uZHVjdCBQQ0Egb24gdHJhaW5pbmcgZGF0YXNldApudW0uY29scyA8LSBuYW1lcyh3aGljaChzYXBwbHkoIFJONTB0cmFpbiwgZnVuY3Rpb24oeCkgaXMubnVtZXJpYyh4KSApKSkKCnBjYSA8LSBwcmNvbXAoUk41MHRyYWluWyxudW0uY29sc10sIHJldHg9VFJVRSwgY2VudGVyPUZBTFNFLCBzY2FsZT1GQUxTRSkKI0VpZ2VudmFsdWVzCmVpZyA8LSAocGNhJHNkZXYpXjIgOyB2YXJpYW5jZSA8LWVpZyoxMDAvc3VtKGVpZykgOyBjdW12YXIgPC0gY3Vtc3VtKHZhcmlhbmNlKSA7IENvbXA8LSAxOmxlbmd0aChjdW12YXIpCgoKCiMjIyBQbG90IGltcG9ydGFuY2UKCnA8LWFzLmRhdGEuZnJhbWUoY2JpbmQoQ29tcCxjdW12YXIpKSAlPiUKICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeCA9ZmFjdG9yKENvbXApLCB5ID0gY3VtdmFyKSkgKyAKICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTk1LCBjb2w9InJlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoImNvbXBvbmVudHMgIH5STjUwdHJhaW4gZmVhdHVyZXMgIikKZ2dwbG90bHkocCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgoKCiNSZXBsYWNlIGZlYXR1cmVzIGJ5IFBDQSBjb21wb25lbnRzClJONTB0cmFpbl9wY2E8LWFzLmRhdGEuZnJhbWUocGNhJHhbLDE6NDBdKQpjb2xuYW1lcyhSTjUwdHJhaW5fcGNhKTwtcGFzdGUoInBjYV9STjUwXyIsMTo0MCxzZXA9IiIpCgojIyMgQVBQTFkgVE8gVEVTVElORyBEQVRBIApSTjUwdGVzdF9wY2E8LWFzLmRhdGEuZnJhbWUocHJlZGljdChwY2EsIG5ld2RhdGE9Uk41MHRlc3RbLG51bS5jb2xzXSlbLDE6NDBdKQpjb2xuYW1lcyhSTjUwdGVzdF9wY2EpPC1wYXN0ZSgicGNhX1JONTBfIiwxOjQwLHNlcD0iIikKCgpSTjUwdHJhaW48LWNiaW5kKFJONTB0cmFpblssMV0sUk41MHRyYWluX3BjYSkKUk41MHRlc3Q8LWNiaW5kKFJONTB0ZXN0WywxXSxSTjUwdGVzdF9wY2EpCgpjb2xuYW1lcyhSTjUwdHJhaW4pWzFdPC1jb2xuYW1lcyhSTjUwdGVzdClbMV08LSJpbWFnZV9uYW1lIgpSTjUwdHJhaW48LWxlZnRfam9pbih0cmFpbkNhdCxSTjUwdHJhaW4sIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikpCgoKIyMjIyBQbG90IEZvdXIgZmlyc3QgZGltZW5zaW9ucwpwIDwtIHBsb3RfbHkoUk41MHRyYWluLCB4ID0gfnBjYV9STjUwXzEsIHkgPSB+cGNhX1JONTBfMiwgY29sb3IgPSB+YXMuZmFjdG9yKHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMicpKSkKCnAKCgoKIyMjIyBQbG90IGZpcnN0ClJONTB0cmFpbiU+JQogICAgcGxvdF9seShhbHBoYSA9IDAuNikgJT4lCiAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9STjUwXzEsIG5hbWU9ImNtcDEiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfUk41MF8yLG5hbWU9ImNtcDIiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9STjUwXzMsIG5hbWU9ImNtcDMiICkgJT4lCiAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9STjUwXzQsIG5hbWU9ImNtcDQiICkgJT4lCiAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1JONTBfNSwgbmFtZT0iY21wNSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1JONTBfNiwgbmFtZT0iY21wNiIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfUk41MF83LCBuYW1lPSJjbXA3IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1JONTBfOCwgbmFtZT0iY21wOCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1JONTBfOSwgbmFtZT0iY21wOSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfUk41MF8xMCwgbmFtZT0iY21wMTAiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQoYmFybW9kZSA9ICJvdmVybGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJSTjUwX291dHB1dHMiKQoKClJONTB0cmFpblsxOjUsMTo1XQpSTjUwdGVzdFsxOjUsMTo1XQpgYGAKCgoKCgoKCgoKIyMjIFZHRzE5IE5ldApgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSB9CgoKIyMjIFJFTU9WRSBORUFSIFpFUk8gVkFSSUFUSU9OCm56dl8xMTwtIG5lYXJaZXJvVmFyKFZHRzE5dHJhaW4pCm56dl8xMjwtIG5lYXJaZXJvVmFyKFZHRzE5dGVzdCkKaWYobGVuZ3RoKHVuaXF1ZShjKG56dl8xMSxuenZfMTIpKSk+MCkKICAgICAgewogICAgICAgIFZHRzE5dHJhaW48LSBWR0cxOXRyYWluWywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICBWR0cxOXRyYWluPC0gVkdHMTl0ZXN0WywgLXVuaXF1ZShjKG56dl8xMSxuenZfMTIpKV0KICAgICAgICB9CgojI0NoZWNrIGNvbnNpc3RlbmN5IGF0IGJvdGggc2V0cwpoZWFkKGNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoVkdHMTl0cmFpblssLTFdLCBtZWFuKSwKICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KFZHRzE5dHJhaW5bLC0xXSwgc2QpLAogICAgICAgICAgICAgICAgdGVzdC5tZWFuID0gbGFwcGx5KFZHRzE5dGVzdFssLTFdLCBtZWFuKSwKICAgICAgICAgICAgICAgICAgICAgIHRlc3Quc2QgPSBsYXBwbHkoVkdHMTl0ZXN0WywtMV0sIHNkKSkpCgoKCiMjIyMgUGxvdCBmaXJzdApWR0cxOXRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDAsIG5hbWU9IlgwIikgJT4lCiAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDEsbmFtZT0iWDEiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflgyLCBuYW1lPSJYMiIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDMsIG5hbWU9IlgzIiApICU+JQogICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg0LCBuYW1lPSJYNCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDUsIG5hbWU9Ilg1IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg2LCBuYW1lPSJYNiIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg3LCBuYW1lPSJYNyIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+WDgsIG5hbWU9Ilg4IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gflg5LCBuYW1lPSJYOSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5YMTAsIG5hbWU9IlgxMCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dChiYXJtb2RlID0gIm92ZXJsYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlZHRzE5dHJhaW5fb3V0cHV0cyIpCgoKIyMjIyBQbG90IGxvZwpWR0cxOXRyYWluJT4lCiAgICBwbG90X2x5KGFscGhhID0gMC42KSAlPiUKICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgwKSwgbmFtZT0iWDAiKSAlPiUKICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDEpLG5hbWU9IlgxIiApICU+JQogICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5sb2coWDIpLCBuYW1lPSJYMiIgKSAlPiUKICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFgzKSwgbmFtZT0iWDMiICkgJT4lCiAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg0KSwgbmFtZT0iWDQiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNSksIG5hbWU9Ilg1IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYNiksIG5hbWU9Ilg2IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+bG9nKFg3KSwgbmFtZT0iWDciICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOCksIG5hbWU9Ilg4IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYOSksIG5hbWU9Ilg5IiApICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfmxvZyhYMTApLCBuYW1lPSJYMTAiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQoYmFybW9kZSA9ICJvdmVybGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJsb2coVkdHMTl0cmFpbl9vdXRwdXRzKSIpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIGNvbmR1Y3QgUENBIG9uIHRyYWluaW5nIGRhdGFzZXQKbnVtLmNvbHMgPC0gbmFtZXMod2hpY2goc2FwcGx5KCBWR0cxOXRyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKcGNhIDwtIHByY29tcChWR0cxOXRyYWluWyxudW0uY29sc10sIHJldHg9VFJVRSwgY2VudGVyPUZBTFNFLCBzY2FsZT1GQUxTRSkKI0VpZ2VudmFsdWVzCmVpZyA8LSAocGNhJHNkZXYpXjIgOyB2YXJpYW5jZSA8LWVpZyoxMDAvc3VtKGVpZykgOyBjdW12YXIgPC0gY3Vtc3VtKHZhcmlhbmNlKSA7IENvbXA8LSAxOmxlbmd0aChjdW12YXIpCgoKCiMjIyBQbG90IGltcG9ydGFuY2UKCnA8LWFzLmRhdGEuZnJhbWUoY2JpbmQoQ29tcCxjdW12YXIpKSAlPiUKICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeCA9ZmFjdG9yKENvbXApLCB5ID0gY3VtdmFyKSkgKyAKICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTk1LCBjb2w9InJlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoImNvbXBvbmVudHMgIH5WR0cxOXRyYWluIGZlYXR1cmVzICIpCmdncGxvdGx5KHApCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKCgojUmVwbGFjZSBmZWF0dXJlcyBieSBQQ0EgY29tcG9uZW50cwpWR0cxOXRyYWluX3BjYTwtYXMuZGF0YS5mcmFtZShwY2EkeFssMTo0MF0pCmNvbG5hbWVzKFZHRzE5dHJhaW5fcGNhKTwtcGFzdGUoInBjYV9WR0cxOV8iLDE6NDAsc2VwPSIiKQoKIyMjIEFQUExZIFRPIFRFU1RJTkcgREFUQSAKVkdHMTl0ZXN0X3BjYTwtYXMuZGF0YS5mcmFtZShwcmVkaWN0KHBjYSwgbmV3ZGF0YT1WR0cxOXRlc3RbLG51bS5jb2xzXSlbLDE6NDBdKQpjb2xuYW1lcyhWR0cxOXRlc3RfcGNhKTwtcGFzdGUoInBjYV9WR0cxOV8iLDE6NDAsc2VwPSIiKQoKClZHRzE5dHJhaW48LWNiaW5kKFZHRzE5dHJhaW5bLDFdLFZHRzE5dHJhaW5fcGNhKQpWR0cxOXRlc3Q8LWNiaW5kKFZHRzE5dGVzdFssMV0sVkdHMTl0ZXN0X3BjYSkKCmNvbG5hbWVzKFZHRzE5dHJhaW4pWzFdPC1jb2xuYW1lcyhWR0cxOXRlc3QpWzFdPC0iaW1hZ2VfbmFtZSIKVkdHMTl0cmFpbjwtbGVmdF9qb2luKHRyYWluQ2F0LFZHRzE5dHJhaW4sIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikpCgoKIyMjIyBQbG90IEZvdXIgZmlyc3QgZGltZW5zaW9ucwpwIDwtIHBsb3RfbHkoVkdHMTl0cmFpbiwgeCA9IH5wY2FfVkdHMTlfMSwgeSA9IH5wY2FfVkdHMTlfMiwgY29sb3IgPSB+YXMuZmFjdG9yKHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMicpKSkKCnAKCgoKIyMjIyBQbG90IGZpcnN0ClZHRzE5dHJhaW4lPiUKICAgIHBsb3RfbHkoYWxwaGEgPSAwLjYpICU+JQogICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfVkdHMTlfMSwgbmFtZT0iY21wMSIpICU+JQogICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9WR0cxOV8yLG5hbWU9ImNtcDIiICkgJT4lCiAgICAgICAgICAgYWRkX2hpc3RvZ3JhbSh4ID0gfnBjYV9WR0cxOV8zLCBuYW1lPSJjbXAzIiApICU+JQogICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfVkdHMTlfNCwgbmFtZT0iY21wNCIgKSAlPiUKICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfVkdHMTlfNSwgbmFtZT0iY21wNSIgKSAlPiUKICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1ZHRzE5XzYsIG5hbWU9ImNtcDYiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1ZHRzE5XzcsIG5hbWU9ImNtcDciICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZF9oaXN0b2dyYW0oeCA9IH5wY2FfVkdHMTlfOCwgbmFtZT0iY21wOCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1ZHRzE5XzksIG5hbWU9ImNtcDkiICkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRfaGlzdG9ncmFtKHggPSB+cGNhX1ZHRzE5XzEwLCBuYW1lPSJjbXAxMCIgKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dChiYXJtb2RlID0gIm92ZXJsYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIlZHRzE5X291dHB1dHMiKQoKClZHRzE5dHJhaW5bMTo1LDE6NV0KVkdHMTl0ZXN0WzE6NSwxOjVdCmBgYAoKCgojR2VuZXJhdGUgb3V0cHV0cwpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSAsZmlnLmFsaWduID0gJ2NlbnRlcicgfQoKdHJhaW5fdjI8LWxlZnRfam9pbihOU0ZXdHJhaW4sIERpc3RyYWluJT4lc2VsZWN0KC10eXBlX2NhdCksIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikgKQp0cmFpbl92MjwtbGVmdF9qb2luKHRyYWluX3YyLCBwSGFzaHRyYWluJT4lc2VsZWN0KC10eXBlX2NhdCksIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikgKQp0cmFpbl92MjwtbGVmdF9qb2luKHRyYWluX3YyLCBJbmNlcHRyYWluJT4lc2VsZWN0KC10eXBlX2NhdCksIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikgKQp0cmFpbl92MjwtbGVmdF9qb2luKHRyYWluX3YyLCBSTjUwdHJhaW4lPiVzZWxlY3QoLXR5cGVfY2F0KSwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiKSApCnRyYWluX3YyPC1sZWZ0X2pvaW4odHJhaW5fdjIsIFZHRzE5dHJhaW4lPiVzZWxlY3QoLXR5cGVfY2F0KSwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiKSApCgpsaWJyYXJ5KHhkYSkKeGRhdHJhaW48LW51bVN1bW1hcnkodHJhaW5fdjIpCnRyYWluX3YyW2lzLm5hKHRyYWluX3YyKV0gPC0gMAp4ZGF0cmFpbjwtbnVtU3VtbWFyeSh0cmFpbl92MikKCnRlc3RfdjI8LWxlZnRfam9pbihOU0ZXdGVzdCwgRGlzdGVzdCwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiICkgKQp0ZXN0X3YyPC1sZWZ0X2pvaW4odGVzdF92MiwgcEhhc2h0ZXN0LCBieT1jKCJpbWFnZV9uYW1lIj0iaW1hZ2VfbmFtZSIpICkKdGVzdF92MjwtbGVmdF9qb2luKHRlc3RfdjIsIEluY2VwdGVzdCwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiKSApCnRlc3RfdjI8LWxlZnRfam9pbih0ZXN0X3YyLCBSTjUwdGVzdCwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiKSApCnRlc3RfdjI8LWxlZnRfam9pbih0ZXN0X3YyLCBWR0cxOXRlc3QsIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikgKQoKeGRhdGVzdDwtbnVtU3VtbWFyeSh0ZXN0X3YyKQp0ZXN0X3YyW2lzLm5hKHRlc3RfdjIpXSA8LSAwCnhkYXRlc3Q8LW51bVN1bW1hcnkodGVzdF92MikKCnRyYWluX3YzPC1sZWZ0X2pvaW4odHJhaW5fdjEsIHRyYWluX3YyJT4lc2VsZWN0KC10eXBlX2NhdCksIGJ5PWMoImltYWdlX25hbWUiPSJpbWFnZV9uYW1lIikgKQp0ZXN0X3YzPC1sZWZ0X2pvaW4odGVzdF92MSwgdGVzdF92MiwgYnk9YygiaW1hZ2VfbmFtZSI9ImltYWdlX25hbWUiICkgKQoKd3JpdGUuY3N2KHRyYWluX3YxLCJ0cmFpbl92MS5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFICkKd3JpdGUuY3N2KHRlc3RfdjEsInRlc3RfdjEuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCgp3cml0ZS5jc3YodHJhaW5fdjIsInRyYWluX3YyLmNzdiIscm93Lm5hbWVzID0gRkFMU0UgKQp3cml0ZS5jc3YodGVzdF92MiwidGVzdF92Mi5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFICkKCndyaXRlLmNzdih0cmFpbl92MywidHJhaW5fdjMuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCndyaXRlLmNzdih0ZXN0X3YzLCJ0ZXN0X3YzLmNzdiIscm93Lm5hbWVzID0gRkFMU0UgKQpgYGAKCgoKCgoKIyMjIGNvcnJlbGF0aW9uICB+cmVzdCBmZWF0dXJlcwpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSAsZmlnLmFsaWduID0gJ2NlbnRlcicgfQoKI3NjYWxlIHRyYWluCmZlYXRfcmVzdF90cmFpbl9zPC0gc2NhbGUoYXMubWF0cml4KGZlYXRfcmVzdF90cmFpbiU+JXNlbGVjdCgtY3JlYXRpb25fdGltZSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgY2VudGVyPVRSVUUsc2NhbGU9VFJVRSkKCiNzY2FsZSB0ZXN0aW5nCmZlYXRfcmVzdF90ZXN0X3M8LSBzY2FsZShhcy5tYXRyaXgoZmVhdF9yZXN0X3Rlc3QlPiVzZWxlY3QoLWNyZWF0aW9uX3RpbWUpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgY2VudGVyPVRSVUUsc2NhbGU9VFJVRSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIoZmVhdF9yZXN0X3RyYWluX3MsICJzY2FsZWQ6Y2VudGVyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIoZmVhdF9yZXN0X3RyYWluX3MsICJzY2FsZWQ6c2NhbGUiKSApCgoKIyNUcmFuc2Zvcm0gYm90aCBzZXRzCmZlYXRfcmVzdF90cmFpbjwtYXMuZGF0YS5mcmFtZShmZWF0X3Jlc3RfdHJhaW5fc1ssXSkKZmVhdF9yZXN0X3Rlc3Q8LWFzLmRhdGEuZnJhbWUoZmVhdF9yZXN0X3Rlc3Rfc1ssXSkKCiMjIENoZWNrCmZlYXRfcmVzdF90cmFpblsxOjUsMTo1XQpmZWF0X3Jlc3RfdGVzdFsxOjUsMTo1XQoKIyMjIFNjYWxlIGFsdAojZmVhdF9yZXN0X3Rlc3Q8LSBzY2FsZShhcy5tYXRyaXgoZmVhdF9yZXN0X3Rlc3QpLCBjZW50ZXIgPSBtZWFuKGZlYXRfcmVzdF90cmFpbiksIHNjYWxlID0gc2QoZmVhdF9yZXN0X3RyYWluKSApKQoKCgojICN0byBkYXRhIGZyYW1lCiMgZmVhdF9yZXN0X3RyYWluX3M8LWFzLmRhdGEuZnJhbWUoZmVhdF9yZXN0X3RyYWluX3MpCiMgICAgIGZlYXRfcmVzdF90ZXN0X3M8LWFzLmRhdGEuZnJhbWUoZmVhdF9yZXN0X3Rlc3RfcykKIyAKIyAKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMwojIHJlcF9yZXN0PC1jYmluZCh0cmFpbi5tZWFuID0gbGFwcGx5KGZlYXRfcmVzdF90cmFpbl9zWywtMV0sIG1lYW4pLAojICAgICAgICAgICAgICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KGZlYXRfcmVzdF90cmFpbl9zWywtMV0sIHNkKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0Lm1lYW4gPSBsYXBwbHkoZmVhdF9yZXN0X3Rlc3Rfc1ssLTFdLCBtZWFuKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Quc2QgPSBsYXBwbHkoZmVhdF9yZXN0X3Rlc3Rfc1ssLTFdLCBzZCkpCiMgaGVhZChyZXBfcmVzdCkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMwoKIyAKIyAjIyMgY2hlY2sgaW4gZGV0YWlsCiMgbGlicmFyeSh4ZGEpCiMgeGRhdHJhaW48LW51bVN1bW1hcnkoZmVhdF9yZXN0X3RyYWluX3MpCiMgaGVhZCh4ZGF0cmFpbikKIyB4ZGF0ZXN0PC1udW1TdW1tYXJ5KGZlYXRfcmVzdF90ZXN0X3MpCiMgaGVhZCh4ZGF0ZXN0KQojICN4ZGF0YWIyPC1jaGFyU3VtbWFyeSh0YWIzKQpgYGAKCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFICxmaWcuYWxpZ24gPSAnY2VudGVyJyB9CgoKI3NjYWxlIHRyYWluCmZlYXRfWDNEX3RyYWluX3M8LSBzY2FsZShhcy5tYXRyaXgoZmVhdF9YM0RfdHJhaW4pLCBjZW50ZXI9VFJVRSxzY2FsZT1UUlVFKQoKI3NjYWxlIHRlc3RpbmcKZmVhdF9YM0RfdGVzdF9zPC0gc2NhbGUoYXMubWF0cml4KGZlYXRfWDNEX3Rlc3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgYXR0cihmZWF0X1gzRF90cmFpbl9zLCAic2NhbGVkOmNlbnRlciIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0cihmZWF0X1gzRF90cmFpbl9zLCAic2NhbGVkOnNjYWxlIikgKQoKCiMjVHJhbnNmb3JtIGJvdGggc2V0cwpmZWF0X1gzRF90cmFpbjwtYXMuZGF0YS5mcmFtZShmZWF0X1gzRF90cmFpbl9zWyxdKQpmZWF0X1gzRF90ZXN0PC1hcy5kYXRhLmZyYW1lKGZlYXRfWDNEX3Rlc3Rfc1ssXSkKCiMjIENoZWNrCmZlYXRfWDNEX3RyYWluWzE6NSwxOjVdCmZlYXRfWDNEX3Rlc3RbMTo1LDE6NV0KIyAKIyAjdG8gZGF0YSBmcmFtZQojIGZlYXRfWDNEX3RyYWluX3M8LWFzLmRhdGEuZnJhbWUoZmVhdF9YM0RfdHJhaW5fcykKIyAgICAgZmVhdF9YM0RfdGVzdF9zPC1hcy5kYXRhLmZyYW1lKGZlYXRfWDNEX3Rlc3RfcykKIyAKIyAKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMwojIHJlcF9YM0Q8LWNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoZmVhdF9YM0RfdHJhaW5fc1ssLTFdLCBtZWFuKSwKIyAgICAgICAgICAgICAgICAgICAgICB0cmFpbi5zZCA9IGxhcHBseShmZWF0X1gzRF90cmFpbl9zWywtMV0sIHNkKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0Lm1lYW4gPSBsYXBwbHkoZmVhdF9YM0RfdGVzdF9zWywtMV0sIG1lYW4pLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC5zZCA9IGxhcHBseShmZWF0X1gzRF90ZXN0X3NbLC0xXSwgc2QpKQojIGhlYWQocmVwX1gzRCkKIyAKIyAKIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMwojIAojIAojICMjIyBjaGVjayBpbiBkZXRhaWwKIyBsaWJyYXJ5KHhkYSkKIyB4ZGF0cmFpbjwtbnVtU3VtbWFyeShmZWF0X1gzRF90cmFpbl9zKQojIGhlYWQoeGRhdHJhaW4pCiMgeGRhdGVzdDwtbnVtU3VtbWFyeShmZWF0X1gzRF90ZXN0X3MpCiMgaGVhZCh4ZGF0ZXN0KQojeGRhdGFiMjwtY2hhCmBgYAoKCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFICxmaWcuYWxpZ24gPSAnY2VudGVyJyB9Cgojc2NhbGUgdHJhaW4KZmVhdF9waXhlbF90cmFpbl9zPC0gc2NhbGUoYXMubWF0cml4KGZlYXRfcGl4ZWxfdHJhaW4pLCBjZW50ZXI9VFJVRSxzY2FsZT1UUlVFKQoKI3NjYWxlIHRlc3RpbmcKZmVhdF9waXhlbF90ZXN0X3M8LSBzY2FsZShhcy5tYXRyaXgoZmVhdF9waXhlbF90ZXN0KSwKICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHIoZmVhdF9waXhlbF90cmFpbl9zLCAic2NhbGVkOmNlbnRlciIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXR0cihmZWF0X3BpeGVsX3RyYWluX3MsICJzY2FsZWQ6c2NhbGUiKSApCgojI1RyYW5zZm9ybSBib3RoIHNldHMKZmVhdF9waXhlbF90cmFpbjwtYXMuZGF0YS5mcmFtZShmZWF0X3BpeGVsX3RyYWluX3NbLF0pCmZlYXRfcGl4ZWxfdGVzdDwtYXMuZGF0YS5mcmFtZShmZWF0X3BpeGVsX3Rlc3Rfc1ssXSkKCiMjIENoZWNrCmZlYXRfcGl4ZWxfdHJhaW5bMTo1LDE6NV0KZmVhdF9waXhlbF90ZXN0WzE6NSwxOjVdCgojIAojIAojIAojICN0byBkYXRhIGZyYW1lCiMgZmVhdF9waXhlbF90cmFpbl9zPC1hcy5kYXRhLmZyYW1lKGZlYXRfcGl4ZWxfdHJhaW5fcykKIyAgICAgZmVhdF9waXhlbF90ZXN0X3M8LWFzLmRhdGEuZnJhbWUoZmVhdF9waXhlbF90ZXN0X3MpCiMgCiMgCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzMKIyByZXBfcGl4ZWw8LWNiaW5kKHRyYWluLm1lYW4gPSBsYXBwbHkoZmVhdF9waXhlbF90cmFpbl9zWywtMV0sIG1lYW4pLAojICAgICAgICAgICAgICAgICAgICAgIHRyYWluLnNkID0gbGFwcGx5KGZlYXRfcGl4ZWxfdHJhaW5fc1ssLTFdLCBzZCksCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC5tZWFuID0gbGFwcGx5KGZlYXRfcGl4ZWxfdGVzdF9zWywtMV0sIG1lYW4pLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC5zZCA9IGxhcHBseShmZWF0X3BpeGVsX3Rlc3Rfc1ssLTFdLCBzZCkpCiMgaGVhZChyZXBfcGl4ZWwpCiMgCiMgCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzMKIyAKIyAKIyAjIyMgY2hlY2sgaW4gZGV0YWlsCiMgbGlicmFyeSh4ZGEpCiMgeGRhdHJhaW48LW51bVN1bW1hcnkoZmVhdF9waXhlbF90cmFpbl9zKQojIGhlYWQoeGRhdHJhaW4pCiMgeGRhdGVzdDwtbnVtU3VtbWFyeShmZWF0X3BpeGVsX3Rlc3RfcykKIyBoZWFkKHhkYXRlc3QpCiMgI3hkYXRhYjI8LWNoYQpgYGAKCgoKIyMjIGNvcnJlbGF0aW9uICB+cGl4ZWwgZmVhdHVyZXMKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgLGZpZy5hbGlnbiA9ICdjZW50ZXInIH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI0VsZWdpbW9zIGxhcyBjb21wb25lbnRlcyBhIHV0aWxpemFyCm51bS5jb2xzIDwtIG5hbWVzKHdoaWNoKHNhcHBseShmZWF0X3BpeGVsX3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKc2V0LnNlZWQoMTIzNCkKbnVtLmNvbHM8LSBzYW1wbGUobnVtLmNvbHMsIDEwMCkKCnN2ZF9zZXE8LWZlYXRfcGl4ZWxfdHJhaW5bLG51bS5jb2xzIF0KIyBDb3JyZWxhdGlvbiBzY2F0dGVyIHBsb3RzIGZvciBhbGwgY29tYmluYXRpb25zIGJldHdlZW4gdGhlIGZpcnN0IGZvdXIgcHJpbmNpcGFsIGNvbXBvbmVudHMuCmxpYnJhcnkocmVzaGFwZTIpCmNvcm1hdCA8LSByb3VuZChjb3Ioc3ZkX3NlcSksNCkKbWVsdGVkX2Nvcm1hdCA8LSBtZWx0KGNvcm1hdCkKaGVhZChtZWx0ZWRfY29ybWF0KQoKCnA8LWdncGxvdChkYXRhID0gbWVsdGVkX2Nvcm1hdCwgYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPXZhbHVlKSkgKyAKICBnZW9tX3RpbGUoKQpnZ3Bsb3RseShwKQpgYGAKCiMjIyBQQ0EgZnJvbSB+cGl4ZWwgZmVhdHVyZXMKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgfQoKIyBjb25kdWN0IFBDQSBvbiB0cmFpbmluZyBkYXRhc2V0Cm51bS5jb2xzIDwtIG5hbWVzKHdoaWNoKHNhcHBseShmZWF0X3BpeGVsX3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKcGNhIDwtIHByY29tcChmZWF0X3BpeGVsX3RyYWluWyxudW0uY29sc10sIHJldHg9VFJVRSwgY2VudGVyPUZBTFNFLCBzY2FsZT1GQUxTRSkKI0VpZ2VudmFsdWVzCmVpZyA8LSAocGNhJHNkZXYpXjIgOyB2YXJpYW5jZSA8LWVpZyoxMDAvc3VtKGVpZykgOyBjdW12YXIgPC0gY3Vtc3VtKHZhcmlhbmNlKSA7IENvbXA8LSAxOmxlbmd0aChjdW12YXIpCgpwPC1hcy5kYXRhLmZyYW1lKGNiaW5kKENvbXAsY3VtdmFyKSkgJT4lCiAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHggPWZhY3RvcihDb21wKSwgeSA9IGN1bXZhcikpICsgCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICArIGdlb21faGxpbmUoeWludGVyY2VwdD05NSwgY29sPSJyZWQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4bGFiKCJjb21wb25lbnRzICB+cGl4ZWwgZmVhdHVyZXMgIikKZ2dwbG90bHkocCkKI1JlcGxhY2UgZmVhdHVyZXMgYnkgUENBIGNvbXBvbmVudHMKZmVhdF9waXhlbF90cmFpbl9wY2E8LWFzLmRhdGEuZnJhbWUocGNhJHhbLDE6MTAwXSkKY29sbmFtZXMoZmVhdF9waXhlbF90cmFpbl9wY2EpPC1wYXN0ZSgicGNhX3BpeGVsXyIsMToxMDAsc2VwPSIiKQoKIyMjIEFQUExZIFRPIFRFU1RJTkcgREFUQSAKZmVhdF9waXhlbF90ZXN0X3BjYTwtYXMuZGF0YS5mcmFtZShwcmVkaWN0KHBjYSwgbmV3ZGF0YT1mZWF0X3BpeGVsX3Rlc3RbLG51bS5jb2xzXSlbLDE6MTAwXSkKY29sbmFtZXMoZmVhdF9waXhlbF90ZXN0X3BjYSk8LXBhc3RlKCJwY2FfcGl4ZWxfIiwxOjEwMCxzZXA9IiIpCgoKYGBgCgoKIyMjIHNjYXR0ZXIgZmlyc3QgNCBkaW1lbnNpb25zCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFICxmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEwICwgZmlnLmFsaWduID0gJ2NlbnRlcicgfQoKbGlicmFyeShwbG90bHkpCgpwYzwtYXMuZGF0YS5mcmFtZShwY2EkeFssMTo0XSklPiUKICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZShEaW0xPVBDMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaW0yPVBDMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaW0zPVBDMywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaW00PVBDNCkKCnAgPC0gcGxvdF9seShwYywgeCA9IH5EaW0xLCB5ID0gfkRpbTIsIGNvbG9yID0gfmFzLmZhY3Rvcih0cmFpbl9pbmRleCR0eXBlX2NhdCkpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTEnKSwKICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTInKSkpCgpwCgpwIDwtIHBsb3RfbHkocGMsIHggPSB+RGltMSwgeSA9IH5EaW0zLCBjb2xvciA9IH5hcy5mYWN0b3IodHJhaW5faW5kZXgkdHlwZV9jYXQpKSAlPiUKICBsYXlvdXQoc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9ICdEaW0xJyksCiAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdEaW0zJykpKQoKcAoKcCA8LSBwbG90X2x5KHBjLCB4ID0gfkRpbTIsIHkgPSB+RGltNCwgY29sb3IgPSB+YXMuZmFjdG9yKHRyYWluX2luZGV4JHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltNCcpKSkKCnAKCgpgYGAKCiMjIyBjb3JyZWxhdGlvbiAgflgzRCBmZWF0dXJlcwpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSAsZmlnLmFsaWduID0gJ2NlbnRlcicgfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojRWxlZ2ltb3MgbGFzIGNvbXBvbmVudGVzIGEgdXRpbGl6YXIKbnVtLmNvbHMgPC0gbmFtZXMod2hpY2goc2FwcGx5KGZlYXRfWDNEX3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKc3ZkX3NlcTwtZmVhdF9YM0RfdHJhaW5bLG51bS5jb2xzIF0KIyBDb3JyZWxhdGlvbiBzY2F0dGVyIHBsb3RzIGZvciBhbGwgY29tYmluYXRpb25zIGJldHdlZW4gdGhlIGZpcnN0IGZvdXIgcHJpbmNpcGFsIGNvbXBvbmVudHMuCmxpYnJhcnkocmVzaGFwZTIpCmNvcm1hdCA8LSByb3VuZChjb3Ioc3ZkX3NlcSksNCkKbWVsdGVkX2Nvcm1hdCA8LSBtZWx0KGNvcm1hdCkKaGVhZChtZWx0ZWRfY29ybWF0KQoKCnA8LWdncGxvdChkYXRhID0gbWVsdGVkX2Nvcm1hdCwgYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPXZhbHVlKSkgKyAKICBnZW9tX3RpbGUoKQpnZ3Bsb3RseShwKQpgYGAKCgojIyMgUENBIGZyb20gflgzRCBmZWF0dXJlcwpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSB9CgojIGNvbmR1Y3QgUENBIG9uIHRyYWluaW5nIGRhdGFzZXQKbnVtLmNvbHMgPC0gbmFtZXMod2hpY2goc2FwcGx5KGZlYXRfWDNEX3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKcGNhIDwtIHByY29tcChmZWF0X1gzRF90cmFpblssbnVtLmNvbHNdLCByZXR4PVRSVUUsIGNlbnRlcj1GQUxTRSwgc2NhbGU9RkFMU0UpCiNFaWdlbnZhbHVlcwplaWcgPC0gKHBjYSRzZGV2KV4yIDsgdmFyaWFuY2UgPC1laWcqMTAwL3N1bShlaWcpIDsgY3VtdmFyIDwtIGN1bXN1bSh2YXJpYW5jZSkgOyBDb21wPC0gMTpsZW5ndGgoY3VtdmFyKQoKcDwtYXMuZGF0YS5mcmFtZShjYmluZChDb21wLGN1bXZhcikpICU+JQogICAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4ID1mYWN0b3IoQ29tcCksIHkgPSBjdW12YXIpKSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSAgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9OTUsIGNvbD0icmVkIikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgeGxhYigiY29tcG9uZW50cyAgflgzRCBmZWF0dXJlcyAiKQpnZ3Bsb3RseShwKQojUmVwbGFjZSBmZWF0dXJlcyBieSBQQ0EgY29tcG9uZW50cwpmZWF0X1gzRF90cmFpbl9wY2E8LWFzLmRhdGEuZnJhbWUocGNhJHhbLDE6MTBdKQpjb2xuYW1lcyhmZWF0X1gzRF90cmFpbl9wY2EpPC1wYXN0ZSgicGNhX1gzRF8iLDE6MTAsc2VwPSIiKQoKIyMjIEFwcGx5IHRvIHRlc3RpbmcKZmVhdF9YM0RfdGVzdF9wY2E8LWFzLmRhdGEuZnJhbWUocHJlZGljdChwY2EsIG5ld2RhdGE9ZmVhdF9YM0RfdGVzdFssbnVtLmNvbHNdKVssMToxMF0pCmNvbG5hbWVzKGZlYXRfWDNEX3Rlc3RfcGNhKTwtcGFzdGUoInBjYV9YM0RfIiwxOjEwLHNlcD0iIikKYGBgCgojIyMgc2NhdHRlciBmaXJzdCA0IGRpbWVuc2lvbnMKYGBge3Igd2FybmluZz0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UgLGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gMTAgLCBmaWcuYWxpZ24gPSAnY2VudGVyJyB9CgpsaWJyYXJ5KHBsb3RseSkKCnBjPC1hcy5kYXRhLmZyYW1lKHBjYSR4WywxOjRdKSU+JQogICAgICAgICAgICAgICAgICAgICAgcmVuYW1lKERpbTE9UEMxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpbTI9UEMyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpbTM9UEMzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpbTQ9UEM0KQoKcCA8LSBwbG90X2x5KHBjLCB4ID0gfkRpbTEsIHkgPSB+RGltMiwgY29sb3IgPSB+YXMuZmFjdG9yKHRyYWluX2luZGV4JHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMicpKSkKCnAKCnAgPC0gcGxvdF9seShwYywgeCA9IH5EaW0xLCB5ID0gfkRpbTMsIGNvbG9yID0gfmFzLmZhY3Rvcih0cmFpbl9pbmRleCR0eXBlX2NhdCkpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTEnKSwKICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTMnKSkpCgpwCgpwIDwtIHBsb3RfbHkocGMsIHggPSB+RGltMiwgeSA9IH5EaW00LCBjb2xvciA9IH5hcy5mYWN0b3IodHJhaW5faW5kZXgkdHlwZV9jYXQpKSAlPiUKICBsYXlvdXQoc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9ICdEaW0xJyksCiAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdEaW00JykpKQoKcAoKCmBgYAoKCiMjIyBBbsOhbGlzaXMgZGUgY29ycmVsYWNpw7NuCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFICxmaWcuYWxpZ24gPSAnY2VudGVyJyB9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiNFbGVnaW1vcyBsYXMgY29tcG9uZW50ZXMgYSB1dGlsaXphcgpudW0uY29scyA8LSBuYW1lcyh3aGljaChzYXBwbHkoZmVhdF9yZXN0X3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKc3ZkX3NlcTwtZmVhdF9yZXN0X3RyYWluWyxudW0uY29scyBdCiMgQ29ycmVsYXRpb24gc2NhdHRlciBwbG90cyBmb3IgYWxsIGNvbWJpbmF0aW9ucyBiZXR3ZWVuIHRoZSBmaXJzdCBmb3VyIHByaW5jaXBhbCBjb21wb25lbnRzLgpsaWJyYXJ5KHJlc2hhcGUyKQpjb3JtYXQgPC0gcm91bmQoY29yKHN2ZF9zZXEpLDQpCm1lbHRlZF9jb3JtYXQgPC0gbWVsdChjb3JtYXQpCmhlYWQobWVsdGVkX2Nvcm1hdCkKCgpwPC1nZ3Bsb3QoZGF0YSA9IG1lbHRlZF9jb3JtYXQsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsgCiAgZ2VvbV90aWxlKCkKZ2dwbG90bHkocCkKYGBgCgoKIyMjIFBDQSBmcm9tIH5yZXN0IGZlYXR1cmVzCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFIH0KCiMgY29uZHVjdCBQQ0Egb24gdHJhaW5pbmcgZGF0YXNldApudW0uY29scyA8LSBuYW1lcyh3aGljaChzYXBwbHkoZmVhdF9yZXN0X3RyYWluLCBmdW5jdGlvbih4KSBpcy5udW1lcmljKHgpICkpKQoKcGNhIDwtIHByY29tcChmZWF0X3Jlc3RfdHJhaW5bLG51bS5jb2xzXSwgcmV0eD1UUlVFLCBjZW50ZXI9RkFMU0UsIHNjYWxlPUZBTFNFKQojRWlnZW52YWx1ZXMKZWlnIDwtIChwY2Ekc2RldileMiA7IHZhcmlhbmNlIDwtZWlnKjEwMC9zdW0oZWlnKSA7IGN1bXZhciA8LSBjdW1zdW0odmFyaWFuY2UpIDsgQ29tcDwtIDE6bGVuZ3RoKGN1bXZhcikKCnA8LWFzLmRhdGEuZnJhbWUoY2JpbmQoQ29tcCxjdW12YXIpKSAlPiUKICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeCA9ZmFjdG9yKENvbXApLCB5ID0gY3VtdmFyKSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTk1LCBjb2w9InJlZCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsYWIoImNvbXBvbmVudHMgIH5YM0QgZmVhdHVyZXMgIikKZ2dwbG90bHkocCkKI1JlcGxhY2UgZmVhdHVyZXMgYnkgUENBIGNvbXBvbmVudHMKZmVhdF9yZXN0X3RyYWluX3BjYTwtYXMuZGF0YS5mcmFtZShwY2EkeFssMToxMl0pCmNvbG5hbWVzKGZlYXRfcmVzdF90cmFpbl9wY2EpPC1wYXN0ZSgicGNhX3Jlc3RfIiwxOjEyLHNlcD0iIikKCiMjIEFwcGx5IHRvIHRlc3RpbmcKZmVhdF9yZXN0X3Rlc3RfcGNhPC1hcy5kYXRhLmZyYW1lKHByZWRpY3QocGNhLCBuZXdkYXRhPWZlYXRfcmVzdF90ZXN0WyxudW0uY29sc10pWywxOjEyXSkKY29sbmFtZXMoZmVhdF9yZXN0X3Rlc3RfcGNhKTwtcGFzdGUoInBjYV9yZXN0XyIsMToxMixzZXA9IiIpCmBgYAoKCiMjIyBzY2F0dGVyIGZpcnN0IDQgZGltZW5zaW9ucwpgYGB7ciB3YXJuaW5nPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSAsZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMCAsIGZpZy5hbGlnbiA9ICdjZW50ZXInIH0KCmxpYnJhcnkocGxvdGx5KQoKcGM8LWFzLmRhdGEuZnJhbWUocGNhJHhbLDE6NF0pJT4lCiAgICAgICAgICAgICAgICAgICAgICByZW5hbWUoRGltMT1QQzEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGltMj1QQzIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGltMz1QQzMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGltND1QQzQpCgpwIDwtIHBsb3RfbHkocGMsIHggPSB+RGltMSwgeSA9IH5EaW0yLCBjb2xvciA9IH5hcy5mYWN0b3IodHJhaW5faW5kZXgkdHlwZV9jYXQpKSAlPiUKICBsYXlvdXQoc2NlbmUgPSBsaXN0KHhheGlzID0gbGlzdCh0aXRsZSA9ICdEaW0xJyksCiAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdEaW0yJykpKQoKcAoKcCA8LSBwbG90X2x5KHBjLCB4ID0gfkRpbTEsIHkgPSB+RGltMywgY29sb3IgPSB+YXMuZmFjdG9yKHRyYWluX2luZGV4JHR5cGVfY2F0KSkgJT4lCiAgbGF5b3V0KHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMScpLAogICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnRGltMycpKSkKCnAKCnAgPC0gcGxvdF9seShwYywgeCA9IH5EaW0yLCB5ID0gfkRpbTQsIGNvbG9yID0gfmFzLmZhY3Rvcih0cmFpbl9pbmRleCR0eXBlX2NhdCkpICU+JQogIGxheW91dChzY2VuZSA9IGxpc3QoeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTEnKSwKICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0RpbTQnKSkpCgpwCgoKCmBgYAoKCgoKIyMjIEFuw6FsaXNpcyBkZSBjb3JyZWxhY2nDs24gWDNEICsgUENBCmBgYHtyIHdhcm5pbmc9IEZBTFNFLCBtZXNzYWdlPUZBTFNFICxmaWcuYWxpZ24gPSAnY2VudGVyJyB9CnRlc3Rjb3I8LWNiaW5kKGZlYXRfWDNEX3RyYWluX3BjYSwgZmVhdF9YM0RfdHJhaW4pCgpzdmRfc2VxPC10ZXN0Y29yCiMgQ29ycmVsYXRpb24gc2NhdHRlciBwbG90cyBmb3IgYWxsIGNvbWJpbmF0aW9ucyBiZXR3ZWVuIHRoZSBmaXJzdCBmb3VyIHByaW5jaXBhbCBjb21wb25lbnRzLgpsaWJyYXJ5KHJlc2hhcGUyKQpjb3JtYXQgPC0gcm91bmQoY29yKHN2ZF9zZXEpLDQpCm1lbHRlZF9jb3JtYXQgPC0gbWVsdChjb3JtYXQpCmhlYWQobWVsdGVkX2Nvcm1hdCkKCgpwPC1nZ3Bsb3QoZGF0YSA9IG1lbHRlZF9jb3JtYXQsIGFlcyh4PVZhcjEsIHk9VmFyMiwgZmlsbD12YWx1ZSkpICsgCiAgZ2VvbV90aWxlKCkKZ2dwbG90bHkocCkKCgojZmVhdF9YM0RfdHJhaW5fcGNhLCBmZWF0X1gzRF90cmFpbiwgZmVhdF9waXhlbF90cmFpbl9wY2EsZmVhdF9yZXN0X3RyYWluX3BjYQoKYGBgCgoKCg==